diff --git a/build/build.proj b/build/build.proj index 2e995c74373..6504d4ae2c7 100644 --- a/build/build.proj +++ b/build/build.proj @@ -225,7 +225,7 @@ Projects="@(SolutionProjects)" Targets="PackProjects" Properties="$(CommonMSBuildProperties); - VisualStudioVersion=$(VisualStudioVersion);" /> + VisualStudioVersion=$(VisualStudioVersion)" /> @@ -11,6 +11,19 @@ true + + $(DefineConstants);NETCORE5_0 + + + + true + false + + + + $(DefineConstants);IS_SIGNING_SUPPORTED + + @@ -333,4 +346,4 @@ - \ No newline at end of file + diff --git a/build/config.props b/build/config.props index 27ff36a9c0e..283fd605370 100644 --- a/build/config.props +++ b/build/config.props @@ -32,12 +32,21 @@ $([MSBuild]::Add(11, $(MajorNuGetVersion))) master int.$(VsTargetBranch) + + rel/d$(VsTargetMajorVersion).$(MinorNuGetVersion) int.d$(VsTargetMajorVersion).$(MinorNuGetVersion) - + + + + true + + master 5.0.100-alpha1-015516 + master + "master 5.0.100-alpha1-015516" $(OverrideCliBranchForTesting) - 3.1 + master $(OverrideCliTargetBranches) master $(OverrideCliTargetBranches) @@ -95,4 +104,7 @@ + + + diff --git a/build/packages.targets b/build/packages.targets index 69b21a7858f..6d1ddfcf698 100644 --- a/build/packages.targets +++ b/build/packages.targets @@ -7,6 +7,8 @@ 16.5.29714.20 16.153.0 16.5.126 + + 5.0.0-alpha1.19473.1 @@ -68,6 +70,8 @@ + + @@ -100,7 +104,6 @@ - diff --git a/build/vsts_build.yaml b/build/vsts_build.yaml index 694bc528af6..ee031683146 100644 --- a/build/vsts_build.yaml +++ b/build/vsts_build.yaml @@ -62,6 +62,16 @@ jobs: Write-Host "##vso[task.setvariable variable=BuildNumber;isOutput=true]$newBuildCounter" Write-Host "##vso[task.setvariable variable=FullVstsBuildNumber;isOutput=true]$FullBuildNumber" + - task: PowerShell@1 + displayName: "Get SDK Version For Build" + name: "getSDKVersionForBuild" + inputs: + scriptType: "inlineScript" + inlineScript: | + $msbuildExe = 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\bin\msbuild.exe' + $SDKVersionForBuild = & $msbuildExe $env:BUILD_REPOSITORY_LOCALPATH\build\config.props /v:m /nologo /t:GetCliVersionForBuilding + Write-Host "##vso[task.setvariable variable=SDKVersionForBuild;isOutput=true]$SDKVersionForBuild" + - task: PowerShell@1 displayName: "Add Build Tags" inputs: @@ -78,6 +88,7 @@ jobs: FullVstsBuildNumber: $[dependencies.Initialize_Build.outputs['updatebuildnumber.FullVstsBuildNumber']] VsTargetChannel: $[dependencies.Initialize_Build.outputs['updatebuildnumber.VsTargetChannel']] VsTargetMajorVersion: $[dependencies.Initialize_Build.outputs['updatebuildnumber.VsTargetMajorVersion']] + SDKVersionForBuild: $[dependencies.Initialize_Build.outputs['getSDKVersionForBuild.SDKVersionForBuild']] LocalizedLanguageCount: "13" pool: @@ -93,6 +104,12 @@ jobs: BuildRTM: "false" steps: + - task: PowerShell@1 + inputs: + scriptName: "$(Build.Repository.LocalPath)\\scripts\\utils\\InstallCLIforBuild.ps1" + arguments: '$(SDKVersionForBuild)' + displayName: "Install .NET 5.0 for build" + - task: PowerShell@1 displayName: "Update Build Number" inputs: @@ -101,6 +118,13 @@ jobs: Write-Host "##vso[build.updatebuildnumber]$env:FullVstsBuildNumber" Get-ChildItem Env: | Sort-Object Name | Format-Table -Wrap -AutoSize + - task: PowerShell@1 + displayName: "Define variables" + inputs: + scriptType: "inlineScript" + inlineScript: | + Write-Host "##vso[task.setvariable variable=Path]${env:AGENT_TEMPDIRECTORY}\dotnet\;${env:Path}" + - task: NuGetToolInstaller@0 displayName: "Use NuGet 5.0.0" inputs: @@ -552,6 +576,7 @@ jobs: variables: BuildNumber: $[dependencies.Initialize_Build.outputs['updatebuildnumber.BuildNumber']] FullVstsBuildNumber: $[dependencies.Initialize_Build.outputs['updatebuildnumber.FullVstsBuildNumber']] + SDKVersionForBuild: $[dependencies.Initialize_Build.outputs['getSDKVersionForBuild.SDKVersionForBuild']] condition: "and(succeeded(),eq(variables['RunFunctionalTestsOnWindows'], 'true')) " pool: name: VSEng-MicroBuildVS2019 @@ -566,6 +591,19 @@ jobs: SkipDesktopAssemblies: "true" steps: + - task: PowerShell@1 + inputs: + scriptName: "$(Build.Repository.LocalPath)\\scripts\\utils\\InstallCLIforBuild.ps1" + arguments: '$(SDKVersionForBuild)' + displayName: "Install .NET 5.0 for build" + + - task: PowerShell@1 + displayName: "Define variables" + inputs: + scriptType: "inlineScript" + inlineScript: | + Write-Host "##vso[task.setvariable variable=Path]${env:AGENT_TEMPDIRECTORY}\dotnet\;${env:Path}" + - task: PowerShell@1 displayName: "Print Environment Variables" inputs: @@ -634,6 +672,7 @@ jobs: timeoutInMinutes: 15 variables: FULLVSTSBUILDNUMBER: $[dependencies.Initialize_Build.outputs['updatebuildnumber.FullVstsBuildNumber']] + SDKVersionForBuild: $[dependencies.Initialize_Build.outputs['getSDKVersionForBuild.SDKVersionForBuild']] MSBUILDDISABLENODEREUSE: 1 condition: "and(succeeded(),eq(variables['RunTestsOnLinux'], 'true')) " pool: @@ -641,6 +680,23 @@ jobs: demands: sh steps: + + - task: ShellScript@2 + displayName: "Install .NET 5.0 for build" + continueOnError: "true" + inputs: + scriptPath: "scripts/utils/InstallCLIforBuild.sh" + disableAutoCwd: "true" + cwd: "$(Build.Repository.LocalPath)" + args: '$(SDKVersionForBuild)' + + - task: PowerShell@2 + displayName: "Define variables" + inputs: + targetType: "inline" + script: | + Write-Host "##vso[task.setvariable variable=PATH]${env:AGENT_TEMPDIRECTORY}/dotnet/:${env:PATH}" + - task: PowerShell@2 displayName: "Update Build Number" inputs: @@ -685,11 +741,21 @@ jobs: timeoutInMinutes: 75 variables: FULLVSTSBUILDNUMBER: $[dependencies.Initialize_Build.outputs['updatebuildnumber.FullVstsBuildNumber']] + SDKVersionForBuild: $[dependencies.Initialize_Build.outputs['getSDKVersionForBuild.SDKVersionForBuild']] condition: "and(succeeded(),eq(variables['RunTestsOnMac'], 'true')) " pool: vmImage: macos-latest - steps: + steps: + - task: ShellScript@2 + displayName: "Install .NET 5.0 for build" + continueOnError: "true" + inputs: + scriptPath: "scripts/utils/InstallCLIforBuild.sh" + disableAutoCwd: "true" + cwd: "$(Build.Repository.LocalPath)" + args: '$(SDKVersionForBuild)' + - task: PowerShell@2 displayName: "Update Build Number" inputs: @@ -699,6 +765,13 @@ jobs: failOnStderr: "true" condition: "always()" + - task: PowerShell@2 + displayName: "Define variables" + inputs: + targetType: "inline" + script: | + Write-Host "##vso[task.setvariable variable=PATH]${env:AGENT_TEMPDIRECTORY}/dotnet/:${env:PATH}" + - task: DownloadBuildArtifacts@0 displayName: "Download NuGet.CommandLine.Test artifacts" inputs: @@ -741,6 +814,7 @@ jobs: timeoutInMinutes: 150 variables: FullVstsBuildNumber: $[dependencies.Initialize_Build.outputs['updatebuildnumber.FullVstsBuildNumber']] + SDKVersionForBuild: $[dependencies.Initialize_Build.outputs['getSDKVersionForBuild.SDKVersionForBuild']] condition: "and(succeeded(),eq(variables['RunEndToEndTests'], 'true')) " pool: name: DDNuGet-Windows @@ -749,6 +823,19 @@ jobs: - Allow_NuGet_E2E_Tests -equals true steps: + - task: PowerShell@1 + inputs: + scriptName: "$(Build.Repository.LocalPath)\\scripts\\utils\\InstallCLIforBuild.ps1" + arguments: '$(SDKVersionForBuild)' + displayName: "Install .NET 5.0 for build" + + - task: PowerShell@1 + displayName: "Define variables" + inputs: + scriptType: "inlineScript" + inlineScript: | + Write-Host "##vso[task.setvariable variable=Path]${env:AGENT_TEMPDIRECTORY}\dotnet\;${env:Path}" + - task: PowerShell@1 displayName: "Print Environment Variables" inputs: @@ -840,6 +927,7 @@ jobs: variables: BuildNumber: $[dependencies.Initialize_Build.outputs['updatebuildnumber.BuildNumber']] FullVstsBuildNumber: $[dependencies.Initialize_Build.outputs['updatebuildnumber.FullVstsBuildNumber']] + SDKVersionForBuild: $[dependencies.Initialize_Build.outputs['getSDKVersionForBuild.SDKVersionForBuild']] condition: "and(succeeded(),eq(variables['RunApexTests'], 'true')) " pool: name: DDNuGet-Windows @@ -866,6 +954,24 @@ jobs: artifactName: "$(VsixPublishDir)" downloadPath: "$(Build.Repository.LocalPath)/artifacts" + - task: NuGetToolInstaller@0 + displayName: "Use NuGet 4.5.0" + inputs: + versionSpec: "4.5.0" + + - task: PowerShell@1 + inputs: + scriptName: "$(Build.Repository.LocalPath)\\scripts\\utils\\InstallCLIforBuild.ps1" + arguments: '$(SDKVersionForBuild)' + displayName: "Install .NET 5.0 for build" + + - task: PowerShell@1 + displayName: "Define variables" + inputs: + scriptType: "inlineScript" + inlineScript: | + Write-Host "##vso[task.setvariable variable=Path]${env:AGENT_TEMPDIRECTORY}\dotnet\;${env:Path}" + - task: MSBuild@1 displayName: "Bootstrap NuGet packages" inputs: @@ -906,14 +1012,6 @@ jobs: # $(System.DefaultWorkingDirectory)\\VSCollect.exe -zip:$(EndToEndResultsDropPath)\\apex-collectlogs.zip # condition: "failed()" - - task: MSBuild@1 - displayName: "Restore for VS2019" - inputs: - solution: "build\\build.proj" - msbuildVersion: "16.0" - configuration: "$(BuildConfiguration)" - msbuildArguments: "/t:RestoreVS /p:BuildNumber=$(BuildNumber)" - - task: NuGetCommand@2 displayName: "Add Apex Feed Source" inputs: diff --git a/global.json b/global.json new file mode 100644 index 00000000000..a32d2892027 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "5.0.100-alpha1" + } +} \ No newline at end of file diff --git a/scripts/funcTests/runFuncTests.sh b/scripts/funcTests/runFuncTests.sh index 1b228bd0c28..5380ca91360 100755 --- a/scripts/funcTests/runFuncTests.sh +++ b/scripts/funcTests/runFuncTests.sh @@ -14,6 +14,10 @@ done RESULTCODE=0 +# print openssl version +echo "===================================================================================================" +openssl version -a +echo "===================================================================================================" # move up to the repo root SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" DIR=$SCRIPTDIR/../.. @@ -32,33 +36,43 @@ chmod +x scripts/funcTests/dotnet-install.sh # Get recommended version for bootstrapping testing version # Issue 8936 - DISABLED TEMPORARILY cli/dotnet-install.sh -i cli -c 2.2 -scripts/funcTests/dotnet-install.sh -i cli -c 2.2 +scripts/funcTests/dotnet-install.sh -i cli -c 2.2 -NoPath +# cli/dotnet-install.sh -runtime dotnet -Channel 2.2 -i cli -NoPath DOTNET="$(pwd)/cli/dotnet" -echo "initial dotnet cli install finished at `date -u +"%Y-%m-%dT%H:%M:%S"`" -#restore solution packages -$DOTNET msbuild -t:restore "$DIR/build/bootstrap.proj" -if [ $? -ne 0 ]; then - echo "Restore failed!!" - exit 1 -fi - -echo "bootstrap project restore finished at `date -u +"%Y-%m-%dT%H:%M:%S"`" +echo "dotnet msbuild build/config.props /v:m /nologo /t:GetCliBranchForTesting" + +# run it twice so dotnet cli can expand and decompress without affecting the result of the target +dotnet msbuild build/config.props /v:m /nologo /t:GetCliBranchForTesting +DOTNET_BRANCHES="$(dotnet msbuild build/config.props /v:m /nologo /t:GetCliBranchForTesting)" +echo $DOTNET_BRANCHES | tr ";" "\n" | while read -r DOTNET_BRANCH +do + echo $DOTNET_BRANCH + ChannelAndVersion=($DOTNET_BRANCH) + Channel=${ChannelAndVersion[0]} + if [ ${#ChannelAndVersion[@]} -eq 1 ] + then + Version="latest" + else + Version=${ChannelAndVersion[1]} + fi + echo "Channel is: $Channel" + echo "Version is: $Version" + scripts/funcTests/dotnet-install.sh -i cli -c $Channel -v $Version -nopath + + # Display current version + $DOTNET --version + dotnet --info +done -echo "$DOTNET msbuild build/config.props /v:m /nologo /t:GetCliBranchForTesting" -DOTNET_BRANCH="$($DOTNET msbuild build/config.props /v:m /nologo /t:GetCliBranchForTesting)" +echo "initial dotnet cli install finished at `date -u +"%Y-%m-%dT%H:%M:%S"`" -echo $DOTNET_BRANCH -# Issue 8936 - TEMPORARILY using direct path to script -scripts/funcTests/dotnet-install.sh -i cli -c $DOTNET_BRANCH +echo "=================" -# Install the 2.x runtime because our tests target netcoreapp2x -# Issue 8936 - TEMPORARILY using direct path to script -scripts/funcTests/dotnet-install.sh -runtime dotnet -Channel 2.2 -i cli -NoPath -# Display current version -$DOTNET --version +# install SDK2 runtime as we encounter problems on running dotnet vstest command when only download SDK3. +cli/dotnet-install.sh -runtime dotnet -Channel 2.2 -i cli -NoPath echo "Deleting .NET Core temporary files" rm -rf "/tmp/"dotnet.* @@ -66,6 +80,15 @@ rm -rf "/tmp/"dotnet.* echo "second dotnet cli install finished at `date -u +"%Y-%m-%dT%H:%M:%S"`" echo "=================" +#restore solution packages +$DOTNET msbuild -t:restore "$DIR/build/bootstrap.proj" +if [ $? -ne 0 ]; then + echo "Restore failed!!" + exit 1 +fi + +echo "bootstrap project restore finished at `date -u +"%Y-%m-%dT%H:%M:%S"`" + # init the repo git submodule init @@ -84,8 +107,8 @@ then fi # restore packages -echo "$DOTNET msbuild build/build.proj /t:Restore /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta" -$DOTNET msbuild build/build.proj /t:Restore /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta +echo "dotnet msbuild build/build.proj /t:Restore /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta" +dotnet msbuild build/build.proj /t:Restore /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta if [ $? -ne 0 ]; then echo "Restore failed!!" exit 1 @@ -94,8 +117,8 @@ fi echo "Restore finished at `date -u +"%Y-%m-%dT%H:%M:%S"`" # Unit tests -echo "$DOTNET msbuild build/build.proj /t:CoreUnitTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta" -$DOTNET msbuild build/build.proj /t:CoreUnitTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta +echo "dotnet msbuild build/build.proj /t:CoreUnitTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta" +dotnet msbuild build/build.proj /t:CoreUnitTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta if [ $? -ne 0 ]; then echo "CoreUnitTests failed!!" @@ -116,8 +139,8 @@ fi echo "Core tests finished at `date -u +"%Y-%m-%dT%H:%M:%S"`" # Func tests -echo "$DOTNET msbuild build/build.proj /t:CoreFuncTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta" -$DOTNET msbuild build/build.proj /t:CoreFuncTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta +echo "dotnet msbuild build/build.proj /t:CoreFuncTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta" +dotnet msbuild build/build.proj /t:CoreFuncTests /p:VisualStudioVersion=16.0 /p:Configuration=Release /p:BuildNumber=1 /p:ReleaseLabel=beta if [ $? -ne 0 ]; then RESULTCODE='1' diff --git a/scripts/utils/InstallCLIforBuild.ps1 b/scripts/utils/InstallCLIforBuild.ps1 new file mode 100644 index 00000000000..c59900e911d --- /dev/null +++ b/scripts/utils/InstallCLIforBuild.ps1 @@ -0,0 +1,48 @@ +# Download the CLI install script to Agent.TempDirectory + +#Write-Host "Installing dotnet CLI into $Env:AGENT_TEMPDIRECTORY folder for building" + +[CmdletBinding(SupportsShouldProcess=$True)] +Param ( + [string]$SDKVersionForBuild +) + +# Get version from SDKVersionForBuild, if only branch name specified, use the latest version for this branch +$CliBranch = $SDKVersionForBuild.trim() +$CliChannelAndVersion = $CliBranch -split "\s+" + +$Channel = $CliChannelAndVersion[0].trim() +if ($CliChannelAndVersion.count -eq 1) { + $Version = 'latest' +}else { + $Version = $CliChannelAndVersion[1].trim() +} + +Write-Host "Channel is : $Channel Version is : $Version" -ForegroundColor Cyan + +$InstallDir = Join-Path $Env:AGENT_TEMPDIRECTORY 'dotnet' + +New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null + +$DotNetInstall = Join-Path $InstallDir 'dotnet-install.ps1' + +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile $DotNetInstall + + +if ([Environment]::Is64BitOperatingSystem) +{ + $arch = "x64"; +} +else +{ + $arch = "x86"; +} + +& $DotNetInstall -Channel $Channel -Version $Version -i $InstallDir -Architecture $arch + +$Env:PATH + +# Display build info +& dotnet --info \ No newline at end of file diff --git a/scripts/utils/InstallCLIforBuild.sh b/scripts/utils/InstallCLIforBuild.sh new file mode 100644 index 00000000000..309021a77d4 --- /dev/null +++ b/scripts/utils/InstallCLIforBuild.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# Download the CLI install script to Agent.TempDirectory + +env + +installVersion=$1 + +echo $installVersion +ChannelAndVersion=($installVersion) +Channel=${ChannelAndVersion[0]} +if [ ${#ChannelAndVersion[@]} -eq 1 ] +then + Version="latest" +else + Version=${ChannelAndVersion[1]} +fi +echo "Channel is: $Channel Version is: $Version" + +echo "Installing dotnet CLI into ${AGENT_TEMPDIRECTORY} folder for building" + +installDir="${AGENT_TEMPDIRECTORY}/dotnet" + +mkdir -p $installDir + +curl -o $installDir/dotnet-install.sh -L https://dot.net/v1/dotnet-install.sh + +# Run install.sh for cli + +chmod +x $installDir/dotnet-install.sh + + +# install master channel to get latest .NET 5 sdks + +# Issue 8936 - DISABLED TEMPORARILY $installDir/dotnet-install.sh -i $installDir -c $Channel -v $Version +chmod +x scripts/funcTests/dotnet-install.sh +scripts/funcTests/dotnet-install.sh -i $installDir -c $Channel -v $Version +#$installDir/dotnet-install.sh -i $installDir -c $Channel -v $Version + +echo "Add ${installDir} to PATH" +PATH=$PATH:${installDir} + +echo $PATH + +echo "Deleting .NET Core temporary files" +rm -rf "/tmp/"dotnet.* + + +# Display current version + +dotnet --info + + + +echo "=================" + diff --git a/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/Microsoft.Build.NuGetSdkResolver.csproj b/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/Microsoft.Build.NuGetSdkResolver.csproj index 436708a75ee..64070ca2a8a 100644 --- a/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/Microsoft.Build.NuGetSdkResolver.csproj +++ b/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/Microsoft.Build.NuGetSdkResolver.csproj @@ -1,4 +1,8 @@  + + true + + diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Pack/NuGet.Build.Tasks.Pack.Sdk2x.targets b/src/NuGet.Core/NuGet.Build.Tasks.Pack/NuGet.Build.Tasks.Pack.Sdk2x.targets new file mode 100644 index 00000000000..a7b505dca41 --- /dev/null +++ b/src/NuGet.Core/NuGet.Build.Tasks.Pack/NuGet.Build.Tasks.Pack.Sdk2x.targets @@ -0,0 +1,15 @@ + + + + + diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Pack/NuGet.Build.Tasks.Pack.csproj b/src/NuGet.Core/NuGet.Build.Tasks.Pack/NuGet.Build.Tasks.Pack.csproj index 53d0286ed8c..49c883a4f4d 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Pack/NuGet.Build.Tasks.Pack.csproj +++ b/src/NuGet.Core/NuGet.Build.Tasks.Pack/NuGet.Build.Tasks.Pack.csproj @@ -1,4 +1,8 @@ - + + + true + + @@ -39,7 +43,7 @@ - + @@ -150,6 +154,7 @@ + @@ -159,20 +164,14 @@ Desktop/ - - Desktop/ - Desktop/ - + CoreCLR/ - - CoreCLR/ - CoreCLR/ diff --git a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.csproj b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.csproj index 97323363dee..b24d9b0ef88 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.csproj +++ b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.csproj @@ -1,4 +1,8 @@ + + true + + @@ -46,7 +50,7 @@ - + diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj b/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj index 940135ef48c..15dd5fd29f3 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj @@ -1,4 +1,8 @@ - + + + true + + diff --git a/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj b/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj index 56435222644..fdd17a2a28b 100644 --- a/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj +++ b/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj @@ -1,4 +1,8 @@ + + true + + @@ -7,7 +11,7 @@ $(TargetFrameworksLibrary) $(NoWarn);CS1591;CS1574;CS1573;CS1584;CS1658 - $(NoWarn);CS1998 + $(NoWarn);CS1998 true true true diff --git a/src/NuGet.Core/NuGet.Commands/SignCommand/CertificateProvider.cs b/src/NuGet.Core/NuGet.Commands/SignCommand/CertificateProvider.cs index d22d3b8d05e..77d8e8a9a80 100644 --- a/src/NuGet.Core/NuGet.Commands/SignCommand/CertificateProvider.cs +++ b/src/NuGet.Core/NuGet.Commands/SignCommand/CertificateProvider.cs @@ -233,4 +233,4 @@ private static bool IsValid(X509Certificate2 certificate, X509Certificate2Collec } } } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Commands/TrustedSignersCommand/TrustedSignerActionsProvider.cs b/src/NuGet.Core/NuGet.Commands/TrustedSignersCommand/TrustedSignerActionsProvider.cs index ce76f9aa0ae..56171d3440c 100644 --- a/src/NuGet.Core/NuGet.Commands/TrustedSignersCommand/TrustedSignerActionsProvider.cs +++ b/src/NuGet.Core/NuGet.Commands/TrustedSignersCommand/TrustedSignerActionsProvider.cs @@ -67,7 +67,7 @@ public async Task SyncTrustedRepositoryAsync(string name, CancellationToken toke throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.Error_TrustedRepositoryDoesNotExist, name)); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Adds a trusted signer item to the settings based a signed package. /// @@ -257,7 +257,7 @@ private void ValidateNoExistingSigner(string name, string serviceIndex, bool val } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private CertificateItem GetCertificateItemForSignature(ISignature signature, bool allowUntrustedRoot = false) { var defaultHashAlgorithm = HashAlgorithmName.SHA256; diff --git a/src/NuGet.Core/NuGet.Credentials/NuGet.Credentials.csproj b/src/NuGet.Core/NuGet.Credentials/NuGet.Credentials.csproj index da26ae78291..c5fd263a5f9 100644 --- a/src/NuGet.Core/NuGet.Credentials/NuGet.Credentials.csproj +++ b/src/NuGet.Core/NuGet.Credentials/NuGet.Credentials.csproj @@ -1,4 +1,8 @@ + + true + + @@ -31,7 +35,7 @@ - + diff --git a/src/NuGet.Core/NuGet.DependencyResolver.Core/NuGet.DependencyResolver.Core.csproj b/src/NuGet.Core/NuGet.DependencyResolver.Core/NuGet.DependencyResolver.Core.csproj index afbd845a8a6..c83b56fde1a 100644 --- a/src/NuGet.Core/NuGet.DependencyResolver.Core/NuGet.DependencyResolver.Core.csproj +++ b/src/NuGet.Core/NuGet.DependencyResolver.Core/NuGet.DependencyResolver.Core.csproj @@ -1,4 +1,8 @@ + + true + + diff --git a/src/NuGet.Core/NuGet.Packaging/NuGet.Packaging.csproj b/src/NuGet.Core/NuGet.Packaging/NuGet.Packaging.csproj index 08fdf73ad3d..b8dc0be568e 100644 --- a/src/NuGet.Core/NuGet.Packaging/NuGet.Packaging.csproj +++ b/src/NuGet.Core/NuGet.Packaging/NuGet.Packaging.csproj @@ -1,4 +1,8 @@ - + + + true + + @@ -7,7 +11,7 @@ $(TargetFrameworksLibrary) $(NoWarn);CS1591;CS1574;CS1573;CS1572 - $(NoWarn);CS0414 + $(NoWarn);CS0414 true true true @@ -45,6 +49,9 @@ + + + diff --git a/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs b/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs index 1b262a896e1..76c4233795d 100644 --- a/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs +++ b/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs @@ -271,7 +271,7 @@ public override async Task GetPrimarySignatureAsync(Cancellati using (var reader = new BinaryReader(bufferedStream, new UTF8Encoding(), leaveOpen: true)) using (var stream = SignedPackageArchiveUtility.OpenPackageSignatureFileStream(reader)) { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED signature = PrimarySignature.Load(stream); #endif } @@ -288,18 +288,15 @@ public override Task IsSignedAsync(CancellationToken token) var isSigned = false; -#if IS_DESKTOP - if (RuntimeEnvironmentHelper.IsWindows) +#if IS_SIGNING_SUPPORTED + using (var zip = new ZipArchive(ZipReadStream, ZipArchiveMode.Read, leaveOpen: true)) { - using (var zip = new ZipArchive(ZipReadStream, ZipArchiveMode.Read, leaveOpen: true)) - { - var signatureEntry = zip.GetEntry(SigningSpecifications.SignaturePath); + var signatureEntry = zip.GetEntry(SigningSpecifications.SignaturePath); - if (signatureEntry != null && - string.Equals(signatureEntry.Name, SigningSpecifications.SignaturePath, StringComparison.Ordinal)) - { - isSigned = true; - } + if (signatureEntry != null && + string.Equals(signatureEntry.Name, SigningSpecifications.SignaturePath, StringComparison.Ordinal)) + { + isSigned = true; } } #endif @@ -322,7 +319,7 @@ public override async Task ValidateIntegrityAsync(SignatureContent signatureCont throw new SignatureException(Strings.SignedPackageNotSignedOnVerify); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using (var bufferedStream = new ReadOnlyBufferedStream(ZipReadStream, leaveOpen: true)) using (var reader = new BinaryReader(bufferedStream, new UTF8Encoding(), leaveOpen: true)) using (var hashAlgorithm = signatureContent.HashAlgorithm.GetHashProvider()) @@ -383,8 +380,8 @@ public override Task GetArchiveHashAsync(HashAlgorithmName hashAlgorithm public override bool CanVerifySignedPackages(SignedPackageVerifierSettings verifierSettings) { -#if IS_DESKTOP - return RuntimeEnvironmentHelper.IsWindows && !RuntimeEnvironmentHelper.IsMono; +#if IS_SIGNING_SUPPORTED + return true; #else return false; #endif @@ -425,4 +422,4 @@ private string GetContentHashForSignedPackage(CancellationToken token) } } } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveIOUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveIOUtility.cs index b186a53dadd..eaaea961af3 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveIOUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveIOUtility.cs @@ -70,8 +70,6 @@ public static void ReadAndWriteUntilPosition(BinaryReader reader, BinaryWriter w /// Read bytes from a BinaryReader and hash them with a given HashAlgorithm and stop when the provided position /// is the current position of the BinaryReader's base stream. It does not hash the byte in the provided position. /// - /// TODO: Once we start supporting signing in Net core, then we should move to another ReadAndHashUntilPosition api which takes Sha512HashFunction which is wrapper - /// over HashAlgorithm and works for desktop as well as net core. /// /// Read bytes from this stream /// HashAlgorithm used to hash contents @@ -111,8 +109,6 @@ public static void ReadAndHashUntilPosition(BinaryReader reader, HashAlgorithm h /// /// Hashes given byte array with a specified HashAlgorithm /// - /// TODO: Once we start supporting signing in Net core, then we should move to another HashBytes api which takes Sha512HashFunction which is wrapper - /// over HashAlgorithm and works for desktop as well as net core. /// /// HashAlgorithm used to hash contents /// Content to hash @@ -127,11 +123,8 @@ public static void HashBytes(HashAlgorithm hashAlgorithm, byte[] bytes) { throw new ArgumentException(Strings.ArgumentCannotBeNullOrEmpty, nameof(bytes)); } -#if IS_DESKTOP + hashAlgorithm.TransformBlock(bytes, 0, bytes.Length, outputBuffer: null, outputOffset: 0); -#else - throw new NotImplementedException(); -#endif } @@ -798,4 +791,4 @@ private static uint DateTimeToDosTime(DateTime dateTime) return (uint)ret; } } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveUtility.cs index 0a51756df99..629c14744cc 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Archive/SignedPackageArchiveUtility.cs @@ -8,7 +8,7 @@ using System.IO; using System.Linq; using System.Security.Cryptography; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using System.Text; @@ -226,7 +226,7 @@ private static bool HasZip64ExtendedInformationExtraField(LocalFileHeader header return false; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Removes repository primary signature (if it exists) or any repository countersignature (if it exists). /// @@ -407,8 +407,6 @@ internal static void UnsignZip(BinaryReader reader, BinaryWriter writer) /// /// Verifies that a signed package archive's signature is valid and it has not been tampered with. /// - /// TODO: When we work to support signing for netcore then we should use GetPackageContentHash api to calculate package hash - /// which works for desktop as well as netcore. /// /// Signed package to verify /// Hash algorithm to be used to hash data. @@ -635,4 +633,4 @@ private static bool CompareHash(byte[] expectedHash, byte[] actualHash) return true; } } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/ISignatureProvider.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/ISignatureProvider.cs index 5667abaf8e6..a19b986df4e 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/ISignatureProvider.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/ISignatureProvider.cs @@ -1,7 +1,6 @@ // 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; using System.Threading; using System.Threading.Tasks; using NuGet.Common; diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/SignPackageRequest.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/SignPackageRequest.cs index db19f8c3887..f855442fe7d 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/SignPackageRequest.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/SignPackageRequest.cs @@ -41,7 +41,7 @@ public abstract class SignPackageRequest : IDisposable internal IX509CertificateChain Chain { get; private set; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// PrivateKey is only used in mssign command. /// @@ -86,7 +86,7 @@ public void Dispose() Certificate?.Dispose(); Chain?.Dispose(); -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED PrivateKey?.Dispose(); #endif @@ -108,4 +108,4 @@ internal void BuildSigningCertificateChainOnce(ILogger logger) } } } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/X509SignatureProvider.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/X509SignatureProvider.cs index ee1eed07fc9..7f7a4090a05 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/X509SignatureProvider.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Authoring/X509SignatureProvider.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using NuGet.Common; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; #endif @@ -97,7 +97,7 @@ public Task CreateRepositoryCountersignatureAsync(RepositorySi } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private static PrimarySignature CreatePrimarySignature(SignPackageRequest request, SignatureContent signatureContent, ILogger logger) { var cmsSigner = SigningUtility.CreateCmsSigner(request, logger); @@ -152,11 +152,11 @@ private static PrimarySignature CreatePrimarySignature(CmsSigner cmsSigner, Sign private static PrimarySignature CreateRepositoryCountersignature(CmsSigner cmsSigner, PrimarySignature primarySignature, CngKey privateKey) { - using (var primarySignatureNativeCms = NativeCms.Decode(primarySignature.GetBytes())) + using (ICms primarySignatureCms = CmsFactory.Create(primarySignature.GetBytes())) { - primarySignatureNativeCms.AddCountersignature(cmsSigner, privateKey); + primarySignatureCms.AddCountersignature(cmsSigner, privateKey); - var bytes = primarySignatureNativeCms.Encode(); + var bytes = primarySignatureCms.Encode(); var updatedCms = new SignedCms(); updatedCms.Decode(bytes); @@ -239,4 +239,4 @@ private Task TimestampRepositoryCountersignatureAsync(SignPack } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Cms/CmsFactory.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/CmsFactory.cs new file mode 100644 index 00000000000..88d698f80be --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/CmsFactory.cs @@ -0,0 +1,34 @@ +// 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; +using System.Security.Cryptography; +using System.Security.Cryptography.Pkcs; + +namespace NuGet.Packaging.Signing +{ + internal static class CmsFactory + { + internal static ICms Create(byte[] cmsBytes) + { + if (cmsBytes == null) + { + throw new ArgumentNullException(nameof(cmsBytes)); + } +#if IS_SIGNING_SUPPORTED + ICms cms = null; +#if IS_DESKTOP + NativeCms nativeCms = NativeCms.Decode(cmsBytes); + cms = new NativeCmsWrapper(nativeCms); +#else + SignedCms signedCms = new SignedCms(); + signedCms.Decode(cmsBytes); + cms = new ManagedCmsWrapper(signedCms); +#endif + return cms; +#else + throw new NotSupportedException(); +#endif + } + } +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Native/HeapBlockRetainer.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/HeapBlockRetainer.cs similarity index 100% rename from src/NuGet.Core/NuGet.Packaging/Signing/Native/HeapBlockRetainer.cs rename to src/NuGet.Core/NuGet.Packaging/Signing/Cms/HeapBlockRetainer.cs diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Cms/ICms.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/ICms.cs new file mode 100644 index 00000000000..e05fedb835b --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/ICms.cs @@ -0,0 +1,28 @@ +// 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; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Security.Cryptography.Pkcs; +using System.Security.Cryptography.X509Certificates; + +namespace NuGet.Packaging.Signing +{ + internal interface ICms : IDisposable + { + byte[] GetPrimarySignatureSignatureValue(); + + byte[] GetRepositoryCountersignatureSignatureValue(); + + void AddCertificates(IEnumerable certificates); + + void AddCountersignature(CmsSigner cmsSigner, CngKey privateKey); + + void AddTimestampToRepositoryCountersignature(SignedCms timestamp); + + void AddTimestamp(SignedCms timestamp); + + byte[] Encode(); + } +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Cms/ManagedCmsWrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/ManagedCmsWrapper.cs new file mode 100644 index 00000000000..43919669f58 --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/ManagedCmsWrapper.cs @@ -0,0 +1,107 @@ +// 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.Collections.Generic; +using System.Security.Cryptography; +using System.Security.Cryptography.Pkcs; +using System.Security.Cryptography.X509Certificates; +using NuGet.Common; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_CORECLR + internal sealed class ManagedCmsWrapper : ICms + { + private readonly SignedCms _signedCms; + + public ManagedCmsWrapper(SignedCms signedCms) + { + _signedCms = signedCms; + } + + public byte[] GetPrimarySignatureSignatureValue() + { + if (_signedCms.SignerInfos.Count != 1) + { + throw new SignatureException(NuGetLogCode.NU3009, Strings.Error_NotOnePrimarySignature); + } + + return _signedCms.SignerInfos[0].GetSignature(); + } + + public byte[] GetRepositoryCountersignatureSignatureValue() + { + if (_signedCms.SignerInfos.Count != 1) + { + throw new SignatureException(NuGetLogCode.NU3009, Strings.Error_NotOnePrimarySignature); + } + else if (_signedCms.SignerInfos[0].CounterSignerInfos.Count == 0) + { + return null; + } + + return _signedCms.SignerInfos[0].CounterSignerInfos[0].GetSignature(); + } + + public void AddCertificates(IEnumerable certificates) + { + foreach (var cert in certificates) + { + _signedCms.AddCertificate(new X509Certificate2(cert)); + } + } + + public void AddCountersignature(CmsSigner cmsSigner, CngKey privateKey) + { + if (_signedCms.SignerInfos.Count != 1) + { + throw new SignatureException(NuGetLogCode.NU3009, Strings.Error_NotOnePrimarySignature); + } + + _signedCms.SignerInfos[0].ComputeCounterSignature(cmsSigner); + } + + public void AddTimestampToRepositoryCountersignature(SignedCms timestamp) + { + var bytes = timestamp.Encode(); + + var unsignedAttribute = new AsnEncodedData(Oids.SignatureTimeStampTokenAttribute, bytes); + + if (_signedCms.SignerInfos.Count != 1) + { + throw new SignatureException(NuGetLogCode.NU3009, Strings.Error_NotOnePrimarySignature); + } + else if (_signedCms.SignerInfos[0].CounterSignerInfos.Count != 1) + { + throw new SignatureException(Strings.Error_NotOneRepositoryCounterSignature); + } + + _signedCms.SignerInfos[0].CounterSignerInfos[0].AddUnsignedAttribute(unsignedAttribute); + } + + public void AddTimestamp(SignedCms timestamp) + { + var bytes = timestamp.Encode(); + + var unsignedAttribute = new AsnEncodedData(Oids.SignatureTimeStampTokenAttribute, bytes); + + if (_signedCms.SignerInfos.Count != 1) + { + throw new SignatureException(NuGetLogCode.NU3009, Strings.Error_NotOnePrimarySignature); + } + + _signedCms.SignerInfos[0].AddUnsignedAttribute(unsignedAttribute); + } + + public byte[] Encode() + { + return _signedCms.Encode(); + } + + public void Dispose() + { + } + } +#endif +} + diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeCms.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeCms.cs similarity index 96% rename from src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeCms.cs rename to src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeCms.cs index 9ec63ab503c..793a0d9f60a 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeCms.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeCms.cs @@ -3,12 +3,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.InteropServices; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography; using System.Security.Cryptography.Pkcs; #endif -using NuGet.Common; +using System.Security.Cryptography.X509Certificates; namespace NuGet.Packaging.Signing @@ -232,17 +233,18 @@ internal static NativeCms Decode(byte[] input) return new NativeCms(handle); } - internal void AddCertificates(IEnumerable encodedCertificates) + internal void AddCertificates(IEnumerable certificates) { - foreach (var cert in encodedCertificates) + foreach (var cert in certificates) { + byte[] encodedCert = cert.RawData; using (var hb = new HeapBlockRetainer()) { - var unmanagedCert = hb.Alloc(cert.Length); - Marshal.Copy(cert, 0, unmanagedCert, cert.Length); + var unmanagedCert = hb.Alloc(encodedCert.Length); + Marshal.Copy(encodedCert, 0, unmanagedCert, encodedCert.Length); var blob = new CRYPT_INTEGER_BLOB() { - cbData = (uint)cert.Length, + cbData = (uint)encodedCert.Length, pbData = unmanagedCert }; @@ -260,7 +262,8 @@ internal void AddCertificates(IEnumerable encodedCertificates) } } } -#if IS_DESKTOP + +#if IS_SIGNING_SUPPORTED internal unsafe void AddCountersignature(CmsSigner cmsSigner, CngKey privateKey) { using (var hb = new HeapBlockRetainer()) @@ -273,12 +276,10 @@ internal unsafe void AddCountersignature(CmsSigner cmsSigner, CngKey privateKey) cCountersigners: 1, rgCountersigners: signerInfo)); - AddCertificates(CertificateUtility.GetRawDataForCollection(cmsSigner.Certificates)); + AddCertificates(cmsSigner.Certificates.OfType()); } } -#endif -#if IS_DESKTOP internal unsafe void AddTimestampToRepositoryCountersignature(SignedCms timestamp) { using (var hb = new HeapBlockRetainer()) @@ -510,7 +511,10 @@ internal byte[] Encode() public void Dispose() { - _handle.Dispose(); + if (!_handle.IsInvalid) + { + _handle.Dispose(); + } } } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeCmsWrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeCmsWrapper.cs new file mode 100644 index 00000000000..e06706b739f --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeCmsWrapper.cs @@ -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. + +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Security.Cryptography.Pkcs; +using System.Security.Cryptography.X509Certificates; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_DESKTOP + internal sealed class NativeCmsWrapper : ICms + { + private readonly NativeCms _nativeCms; + + public NativeCmsWrapper(NativeCms nativeCms) + { + _nativeCms = nativeCms; + } + + public byte[] GetPrimarySignatureSignatureValue() + { + return _nativeCms.GetPrimarySignatureSignatureValue(); + } + + public byte[] GetRepositoryCountersignatureSignatureValue() + { + return _nativeCms.GetRepositoryCountersignatureSignatureValue(); + } + + public void AddCertificates(IEnumerable certificates) + { + _nativeCms.AddCertificates(certificates); + } + + public void AddCountersignature(CmsSigner cmsSigner, CngKey privateKey) + { + _nativeCms.AddCountersignature(cmsSigner, privateKey); + } + + public void AddTimestampToRepositoryCountersignature(SignedCms timestamp) + { + _nativeCms.AddTimestampToRepositoryCountersignature(timestamp); + } + + public void AddTimestamp(SignedCms timestamp) + { + _nativeCms.AddTimestamp(timestamp); + } + + public byte[] Encode() + { + return _nativeCms.Encode(); + } + + public void Dispose() + { + _nativeCms.Dispose(); + } + } +#endif +} + diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeMethods.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeMethods.cs similarity index 100% rename from src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeMethods.cs rename to src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeMethods.cs diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeUtility.cs similarity index 99% rename from src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeUtility.cs rename to src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeUtility.cs index 498baeddae0..9c49d0a5e9e 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Native/NativeUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Cms/NativeUtility.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography; using System.Security.Cryptography.Pkcs; #endif @@ -28,7 +28,7 @@ internal static void ThrowIfFailed(bool result) } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED internal static SignedCms NativeSign(CmsSigner cmsSigner, byte[] data, CngKey privateKey) { using (var hb = new HeapBlockRetainer()) @@ -206,4 +206,4 @@ internal unsafe static CMSG_SIGNER_ENCODE_INFO CreateSignerInfo( } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Package/ISignedPackageWriter.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Package/ISignedPackageWriter.cs index d7e12e5620a..d8fcaf2cd43 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Package/ISignedPackageWriter.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Package/ISignedPackageWriter.cs @@ -14,7 +14,7 @@ namespace NuGet.Packaging.Signing /// public interface ISignedPackageWriter { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Removes a signature if it exists. /// diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/AuthorPrimarySignature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/AuthorPrimarySignature.cs index f3e3a9dad97..92d94b5ccc8 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/AuthorPrimarySignature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/AuthorPrimarySignature.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; #endif @@ -14,8 +14,7 @@ namespace NuGet.Packaging.Signing { public sealed class AuthorPrimarySignature : PrimarySignature { -#if IS_DESKTOP - +#if IS_SIGNING_SUPPORTED public AuthorPrimarySignature(SignedCms signedCms) : base(signedCms, SignatureType.Author) { @@ -46,4 +45,4 @@ public override SignatureVerificationSummary Verify( } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/IRepositorySignature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/IRepositorySignature.cs index 5484db85993..0d1b8bd8352 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/IRepositorySignature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/IRepositorySignature.cs @@ -8,7 +8,7 @@ namespace NuGet.Packaging.Signing { public interface IRepositorySignature : ISignature { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED Uri V3ServiceIndexUrl { get; } IReadOnlyList PackageOwners { get; } diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/ISignature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/ISignature.cs index 6d8dd83e3e4..78f91b437de 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/ISignature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/ISignature.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif @@ -9,7 +9,7 @@ namespace NuGet.Packaging.Signing { public interface ISignature { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED SignatureType Type { get; } SignerInfo SignerInfo { get; } diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignature.cs index a3c72454f90..5ae8a65f7c6 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignature.cs @@ -4,7 +4,7 @@ using System; using System.IO; using System.Security.Cryptography; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using NuGet.Common; @@ -13,7 +13,7 @@ namespace NuGet.Packaging.Signing { public abstract class PrimarySignature : Signature { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// A SignedCms object holding the signature and SignerInfo. /// @@ -105,9 +105,9 @@ public static PrimarySignature Load(Stream stream) public override byte[] GetSignatureValue() { - using (var nativeCms = NativeCms.Decode(SignedCms.Encode())) + using (ICms cms = CmsFactory.Create(SignedCms.Encode())) { - return nativeCms.GetPrimarySignatureSignatureValue(); + return cms.GetPrimarySignatureSignatureValue(); } } @@ -128,7 +128,6 @@ protected static void ThrowForInvalidPrimarySignature() throw new SignatureException(NuGetLogCode.NU3011, Strings.InvalidPrimarySignature); } - private static void VerifySigningCertificate( SignedCms signedCms, SignerInfo signerInfo, diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignatureFactory.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignatureFactory.cs index 9996b73d86e..7ba4392cb3e 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignatureFactory.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/PrimarySignatureFactory.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; using NuGet.Common; #endif @@ -10,7 +10,7 @@ namespace NuGet.Packaging.Signing { public static class PrimarySignatureFactory { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public static PrimarySignature CreateSignature(SignedCms signedCms) { var signatureType = AttributeUtility.GetSignatureType(signedCms.SignerInfos[0].SignedAttributes); diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryCountersignature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryCountersignature.cs index 6ec17d963c3..bb4ad146ce9 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryCountersignature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryCountersignature.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; #endif @@ -15,7 +15,7 @@ namespace NuGet.Packaging.Signing { public sealed class RepositoryCountersignature : Signature, IRepositorySignature { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private readonly PrimarySignature _primarySignature; public Uri V3ServiceIndexUrl { get; } @@ -78,9 +78,9 @@ public static RepositoryCountersignature GetRepositoryCountersignature(PrimarySi public override byte[] GetSignatureValue() { - using (var nativeCms = NativeCms.Decode(_primarySignature.GetBytes())) + using (ICms cms = CmsFactory.Create(_primarySignature.GetBytes())) { - return nativeCms.GetRepositoryCountersignatureSignatureValue(); + return cms.GetRepositoryCountersignatureSignatureValue(); } } diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryPrimarySignature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryPrimarySignature.cs index 975c3ba559d..b1dd3fecf9d 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryPrimarySignature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/RepositoryPrimarySignature.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; #endif @@ -15,7 +15,7 @@ namespace NuGet.Packaging.Signing { public sealed class RepositoryPrimarySignature : PrimarySignature, IRepositorySignature { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public Uri V3ServiceIndexUrl { get; } public IReadOnlyList PackageOwners { get; } @@ -57,4 +57,4 @@ public override SignatureVerificationSummary Verify( } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/Signature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/Signature.cs index 2ad15893563..d61d62426f5 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/Signature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/Signature.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; @@ -20,7 +20,7 @@ namespace NuGet.Packaging.Signing /// public abstract class Signature : ISignature { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private readonly Lazy> _timestamps; /// diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/UnknownPrimarySignature.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/UnknownPrimarySignature.cs index 3b3e943c019..96e473da74c 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/UnknownPrimarySignature.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Signatures/UnknownPrimarySignature.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif @@ -9,7 +9,7 @@ namespace NuGet.Packaging.Signing { public sealed class UnknownPrimarySignature : PrimarySignature { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public UnknownPrimarySignature(SignedCms signedCms) : base(signedCms, SignatureType.Unknown) { diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampRequest.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampRequest.cs new file mode 100644 index 00000000000..5c0b661cdee --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampRequest.cs @@ -0,0 +1,13 @@ +// 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; +using System.Threading.Tasks; + +namespace NuGet.Packaging.Signing +{ + internal interface IRfc3161TimestampRequest + { + Task SubmitRequestAsync(Uri timestampUri, TimeSpan timeout); + } +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampToken.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampToken.cs new file mode 100644 index 00000000000..c6f381483b4 --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampToken.cs @@ -0,0 +1,17 @@ +// 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.Pkcs; + +namespace NuGet.Packaging.Signing +{ + internal interface IRfc3161TimestampToken + { +#if IS_SIGNING_SUPPORTED + IRfc3161TimestampTokenInfo TokenInfo { get; } + + SignedCms AsSignedCms(); +#endif + } +} + diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampTokenInfo.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampTokenInfo.cs new file mode 100644 index 00000000000..d38f39bf25f --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/IRfc3161TimestampTokenInfo.cs @@ -0,0 +1,25 @@ +// 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; +using System.Security.Cryptography; + +namespace NuGet.Packaging.Signing +{ + internal interface IRfc3161TimestampTokenInfo + { +#if IS_SIGNING_SUPPORTED + string PolicyId { get; } + + DateTimeOffset Timestamp { get; } + + long? AccuracyInMicroseconds { get; } + + Oid HashAlgorithmId { get; } + + bool HasMessageHash(byte[] hash); + + byte[] GetNonce(); +#endif + } +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampProvider.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampProvider.cs index 09b8d6bbced..e5494db1b57 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampProvider.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampProvider.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Security.Cryptography; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif @@ -26,11 +26,11 @@ public class Rfc3161TimestampProvider : ITimestampProvider { // Url to an RFC 3161 timestamp server private readonly Uri _timestamperUrl; - private const int _rfc3161RequestTimeoutSeconds = 10; + private static readonly TimeSpan RequestTimeout = TimeSpan.FromSeconds(10); public Rfc3161TimestampProvider(Uri timeStampServerUrl) { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED // Uri.UriSchemeHttp and Uri.UriSchemeHttps are not available in netstandard 1.3 if (!string.Equals(timeStampServerUrl.Scheme, Uri.UriSchemeHttp, StringComparison.Ordinal) && !string.Equals(timeStampServerUrl.Scheme, Uri.UriSchemeHttps, StringComparison.Ordinal)) @@ -46,32 +46,32 @@ public Rfc3161TimestampProvider(Uri timeStampServerUrl) _timestamperUrl = timeStampServerUrl ?? throw new ArgumentNullException(nameof(timeStampServerUrl)); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Timestamps data present in the TimestampRequest. /// - public Task TimestampSignatureAsync(PrimarySignature primarySignature, TimestampRequest request, ILogger logger, CancellationToken token) + public async Task TimestampSignatureAsync(PrimarySignature primarySignature, TimestampRequest request, ILogger logger, CancellationToken token) { - var timestampCms = GetTimestamp(request, logger, token); - using (var signatureNativeCms = NativeCms.Decode(primarySignature.GetBytes())) + SignedCms timestampCms = await GetTimestampAsync(request, logger, token); + using (ICms signatureCms = CmsFactory.Create(primarySignature.GetBytes())) { if (request.Target == SignaturePlacement.Countersignature) { - signatureNativeCms.AddTimestampToRepositoryCountersignature(timestampCms); + signatureCms.AddTimestampToRepositoryCountersignature(timestampCms); } else { - signatureNativeCms.AddTimestamp(timestampCms); + signatureCms.AddTimestamp(timestampCms); } - return Task.FromResult(PrimarySignature.Load(signatureNativeCms.Encode())); + return PrimarySignature.Load(signatureCms.Encode()); } } /// /// Timestamps data present in the TimestampRequest. /// - public SignedCms GetTimestamp(TimestampRequest request, ILogger logger, CancellationToken token) + public async Task GetTimestampAsync(TimestampRequest request, ILogger logger, CancellationToken token) { token.ThrowIfCancellationRequested(); @@ -87,17 +87,19 @@ public SignedCms GetTimestamp(TimestampRequest request, ILogger logger, Cancella // Allows us to track the request. var nonce = GenerateNonce(); - var rfc3161TimestampRequest = new Rfc3161TimestampRequest( + var rfc3161TimestampRequest = Rfc3161TimestampRequestFactory.Create( request.HashedMessage, request.HashAlgorithm.ConvertToSystemSecurityHashAlgorithmName(), + requestedPolicyId: null, nonce: nonce, - requestSignerCertificates: true); + requestSignerCertificates: true, + extensions: null); // Request a timestamp // The response status need not be checked here as lower level api will throw if the response is invalid - var timestampToken = rfc3161TimestampRequest.SubmitRequest( + IRfc3161TimestampToken timestampToken = await rfc3161TimestampRequest.SubmitRequestAsync( _timestamperUrl, - TimeSpan.FromSeconds(_rfc3161RequestTimeoutSeconds)); + RequestTimeout); // quick check for response validity ValidateTimestampResponse(nonce, request.HashedMessage, timestampToken); @@ -124,16 +126,15 @@ public SignedCms GetTimestamp(TimestampRequest request, ILogger logger, Cancella } private static SignedCms EnsureCertificatesInCertificatesCollection( - SignedCms timestampCms, + SignedCms timestamp, IReadOnlyList chain) { - using (var timestampNativeCms = NativeCms.Decode(timestampCms.Encode())) + using (ICms timestampCms = CmsFactory.Create(timestamp.Encode())) { - timestampNativeCms.AddCertificates( - chain.Where(certificate => !timestampCms.Certificates.Contains(certificate)) - .Select(certificate => certificate.RawData)); + timestampCms.AddCertificates( + chain.Where(certificate => !timestamp.Certificates.Contains(certificate))); - var bytes = timestampNativeCms.Encode(); + var bytes = timestampCms.Encode(); var updatedCms = new SignedCms(); updatedCms.Decode(bytes); @@ -142,7 +143,7 @@ private static SignedCms EnsureCertificatesInCertificatesCollection( } } - private static void ValidateTimestampCms(SigningSpecifications spec, SignedCms timestampCms, Rfc3161TimestampToken timestampToken) + private static void ValidateTimestampCms(SigningSpecifications spec, SignedCms timestampCms, IRfc3161TimestampToken timestampToken) { var signerInfo = timestampCms.SignerInfos[0]; try @@ -203,7 +204,7 @@ private static void ValidateTimestampCms(SigningSpecifications spec, SignedCms t } } - private static void ValidateTimestampResponse(byte[] nonce, byte[] messageHash, Rfc3161TimestampToken timestampToken) + private static void ValidateTimestampResponse(byte[] nonce, byte[] messageHash, IRfc3161TimestampToken timestampToken) { if (!nonce.SequenceEqual(timestampToken.TokenInfo.GetNonce())) { @@ -233,6 +234,17 @@ private static byte[] GenerateNonce() rng.GetBytes(nonce); } + EnsureValidNonce(nonce); + + return nonce; + } + + /// + /// Non-private for testing purposes only. + /// + internal static void EnsureValidNonce(byte[] nonce) + { +#if IS_DESKTOP // Eventually, CryptEncodeObjectEx(...) is called on a CRYPT_TIMESTAMP_REQUEST with this nonce, // and CryptEncodeObjectEx(...) interprets the nonce as a little endian, DER-encoded integer value // (without tag and length), and may even strip leading bytes from the big endian representation @@ -247,8 +259,12 @@ private static byte[] GenerateNonce() nonce[nonce.Length - 1] &= 0x7f; nonce[nonce.Length - 1] |= 0x01; - - return nonce; +#else + // Per documentation on Rfc3161TimestampRequest.CreateFromHash(...) the nonce "value is interpreted + // as an unsigned big-endian integer and may be normalized to the encoding format." Clear the sign bit on + // the most significant byte to ensure the nonce represents an unsigned big endian integer. + nonce[0] &= 0x7f; +#endif } #else @@ -262,4 +278,4 @@ public Task TimestampSignatureAsync(PrimarySignature primarySi } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequest.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequest.cs index 4ae973efcc5..2a84e39ba69 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequest.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequest.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -180,7 +179,7 @@ public Rfc3161TimestampRequest( public X509ExtensionCollection GetExtensions() => Rfc3161TimestampTokenInfo.ShallowCopy(Data._extensions, preserveNull: false); - public unsafe Rfc3161TimestampToken SubmitRequest(Uri timestampUri, TimeSpan timeout) + public unsafe IRfc3161TimestampToken SubmitRequest(Uri timestampUri, TimeSpan timeout) { if (timestampUri == null) throw new ArgumentNullException(nameof(timestampUri)); @@ -239,7 +238,7 @@ public unsafe Rfc3161TimestampToken SubmitRequest(Uri timestampUri, TimeSpan tim byte[] encoded = new byte[content.cbEncoded]; Marshal.Copy(content.pbEncoded, encoded, 0, content.cbEncoded); - Rfc3161TimestampTokenInfo tstInfo = new Rfc3161TimestampTokenInfo(pTsContext); + var tstInfo = new Rfc3161TimestampTokenInfoNet472Wrapper(new Rfc3161TimestampTokenInfo(pTsContext)); X509Certificate2 signerCert = new X509Certificate2(pTsSigner); using (X509Store extraCerts = new X509Store(hStore)) @@ -254,7 +253,7 @@ public unsafe Rfc3161TimestampToken SubmitRequest(Uri timestampUri, TimeSpan tim } } - return new Rfc3161TimestampToken( + return Rfc3161TimestampTokenFactory.Create( tstInfo, signerCert, additionalCertsColl, diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestFactory.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestFactory.cs new file mode 100644 index 00000000000..3e291d7bb40 --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestFactory.cs @@ -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. + +using System; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +namespace NuGet.Packaging.Signing +{ + internal sealed class Rfc3161TimestampRequestFactory + { + public static IRfc3161TimestampRequest Create( + byte[] messageHash, + HashAlgorithmName hashAlgorithm, + Oid requestedPolicyId, + byte[] nonce, + bool requestSignerCertificates, + X509ExtensionCollection extensions) + { + if (messageHash == null) + { + throw new ArgumentNullException(nameof(messageHash)); + } +#if IS_SIGNING_SUPPORTED + IRfc3161TimestampRequest iRfc3161TimestampRequest = null; +#if IS_DESKTOP + iRfc3161TimestampRequest = new Rfc3161TimestampRequestNet472Wrapper( + messageHash, + hashAlgorithm, + requestedPolicyId, + nonce, + requestSignerCertificates, + extensions); +#else + iRfc3161TimestampRequest = new Rfc3161TimestampRequestNetstandard21Wrapper( + messageHash, + hashAlgorithm, + requestedPolicyId, + nonce, + requestSignerCertificates, + extensions); +#endif + return iRfc3161TimestampRequest; +#else + throw new NotSupportedException(); +#endif + } + } +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestNet472Wrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestNet472Wrapper.cs new file mode 100644 index 00000000000..3df66efde6a --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestNet472Wrapper.cs @@ -0,0 +1,39 @@ +// 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; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_DESKTOP + internal sealed class Rfc3161TimestampRequestNet472Wrapper : IRfc3161TimestampRequest + { + private readonly Rfc3161TimestampRequest _rfc3161TimestampRequest; + + public Rfc3161TimestampRequestNet472Wrapper( + byte[] messageHash, + HashAlgorithmName hashAlgorithm, + Oid requestedPolicyId, + byte[] nonce, + bool requestSignerCertificates, + X509ExtensionCollection extensions) + { + _rfc3161TimestampRequest = new Rfc3161TimestampRequest( + messageHash, + hashAlgorithm, + requestedPolicyId, + nonce, + requestSignerCertificates, + extensions); + } + + public Task SubmitRequestAsync(Uri timestampUri, TimeSpan timeout) + { + return Task.FromResult(_rfc3161TimestampRequest.SubmitRequest(timestampUri, timeout)); + } + } +#endif +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestNetstandard21Wrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestNetstandard21Wrapper.cs new file mode 100644 index 00000000000..6bbf67cab7c --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampRequestNetstandard21Wrapper.cs @@ -0,0 +1,90 @@ +// 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; +using System.Globalization; +#if IS_SIGNING_SUPPORTED && IS_CORECLR +using System.Net.Http; +using System.Net.Http.Headers; +#endif +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_CORECLR + internal sealed class Rfc3161TimestampRequestNetstandard21Wrapper : IRfc3161TimestampRequest + { + private static readonly HttpClient HttpClient = new HttpClient(); + private readonly System.Security.Cryptography.Pkcs.Rfc3161TimestampRequest _rfc3161TimestampRequest; + + public Rfc3161TimestampRequestNetstandard21Wrapper( + byte[] messageHash, + HashAlgorithmName hashAlgorithm, + Oid requestedPolicyId, + byte[] nonce, + bool requestSignerCertificates, + X509ExtensionCollection extensions) + { + _rfc3161TimestampRequest = System.Security.Cryptography.Pkcs.Rfc3161TimestampRequest.CreateFromHash( + new ReadOnlyMemory(messageHash), + hashAlgorithm, + requestedPolicyId, + nonce, + requestSignerCertificates, + extensions); + } + + public async Task SubmitRequestAsync(Uri timestampUri, TimeSpan timeout) + { + if (timestampUri == null) + { + throw new ArgumentNullException(nameof(timestampUri)); + } + + if (!timestampUri.IsAbsoluteUri) + { + throw new ArgumentException( + Strings.AnAbsoluteUriIsRequired, nameof(timestampUri)); + } + + if (timestampUri.Scheme != Uri.UriSchemeHttp && timestampUri.Scheme != Uri.UriSchemeHttps) + { + throw new ArgumentException( + Strings.HttpOrHttpsIsRequired, nameof(timestampUri)); + } + + using (var content = new ReadOnlyMemoryContent(_rfc3161TimestampRequest.Encode())) + { + content.Headers.ContentType = new MediaTypeHeaderValue("application/timestamp-query"); + using (HttpResponseMessage httpResponse = await HttpClient.PostAsync(timestampUri, content)) + { + if (!httpResponse.IsSuccessStatusCode) + { + throw new CryptographicException( + string.Format( + CultureInfo.CurrentCulture, + Strings.TimestampServiceRespondedError, + (int)httpResponse.StatusCode, + httpResponse.ReasonPhrase)); + } + + if (!string.Equals(httpResponse.Content.Headers.ContentType.MediaType, "application/timestamp-response", StringComparison.OrdinalIgnoreCase)) + { + throw new CryptographicException(Strings.TimestampServiceRespondedInvalidFormat); + } + + var data = await httpResponse.Content.ReadAsByteArrayAsync(); + + System.Security.Cryptography.Pkcs.Rfc3161TimestampToken response = _rfc3161TimestampRequest.ProcessResponse(data, out var _); + + var timestampToken = new Rfc3161TimestampTokenNetstandard21Wrapper(response); + + return timestampToken; + } + } + } + } +#endif +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampToken.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampToken.cs index 39eb96dea43..0031ff3c0f3 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampToken.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampToken.cs @@ -26,12 +26,12 @@ internal sealed class Rfc3161TimestampToken private readonly byte[] _encoded; - public Rfc3161TimestampTokenInfo TokenInfo { get; } + public IRfc3161TimestampTokenInfo TokenInfo { get; } public X509Certificate2 SignerCertificate { get; } public X509Certificate2Collection AdditionalCerts { get; } internal Rfc3161TimestampToken( - Rfc3161TimestampTokenInfo tstInfo, + IRfc3161TimestampTokenInfo tstInfo, X509Certificate2 signerCertificate, X509Certificate2Collection additionalCerts, byte[] encoded) @@ -121,7 +121,7 @@ private static Rfc3161TimestampToken CryptVerifyTimeStampSignature(byte[] encode throw new CryptographicException(Marshal.GetLastWin32Error()); } - Rfc3161TimestampTokenInfo tstInfo = new Rfc3161TimestampTokenInfo(pTsContext); + IRfc3161TimestampTokenInfo tstInfo = new Rfc3161TimestampTokenInfoNet472Wrapper(new Rfc3161TimestampTokenInfo(pTsContext)); X509Certificate2 signerCert = new X509Certificate2(pTsSigner); using (X509Store extraCerts = new X509Store(hStore)) diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenFactory.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenFactory.cs new file mode 100644 index 00000000000..02aa3e9d42f --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenFactory.cs @@ -0,0 +1,57 @@ +// 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; +using System.Security.Cryptography.X509Certificates; + +namespace NuGet.Packaging.Signing +{ + internal sealed class Rfc3161TimestampTokenFactory + { + public static IRfc3161TimestampToken Create( + IRfc3161TimestampTokenInfo tstInfo, + X509Certificate2 signerCertificate, + X509Certificate2Collection additionalCerts, + byte[] encoded) + { + if (tstInfo == null) + { + throw new ArgumentNullException(nameof(tstInfo)); + } + + if (signerCertificate == null) + { + throw new ArgumentNullException(nameof(signerCertificate)); + } + + if (additionalCerts == null) + { + throw new ArgumentNullException(nameof(additionalCerts)); + } + + if (encoded == null) + { + throw new ArgumentNullException(nameof(encoded)); + } +#if IS_SIGNING_SUPPORTED + IRfc3161TimestampToken iRfc3161TimestampToken = null; +#if IS_DESKTOP + iRfc3161TimestampToken = new Rfc3161TimestampTokenNet472Wrapper( + tstInfo, + signerCertificate, + additionalCerts, + encoded); +#else + iRfc3161TimestampToken = new Rfc3161TimestampTokenNetstandard21Wrapper( + tstInfo, + signerCertificate, + additionalCerts, + encoded); +#endif + return iRfc3161TimestampToken; +#else + throw new NotSupportedException(); +#endif + } + } +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoFactory.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoFactory.cs new file mode 100644 index 00000000000..e5c86bb4815 --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoFactory.cs @@ -0,0 +1,30 @@ +// 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; +using System.Security.Cryptography; + +namespace NuGet.Packaging.Signing +{ + internal sealed class Rfc3161TimestampTokenInfoFactory + { + public static IRfc3161TimestampTokenInfo Create(byte[] bytes) + { + if (bytes == null) + { + throw new ArgumentNullException(nameof(bytes)); + } +#if IS_SIGNING_SUPPORTED + IRfc3161TimestampTokenInfo iRfc3161TimestampTokenInfo = null; +#if IS_DESKTOP + iRfc3161TimestampTokenInfo = new Rfc3161TimestampTokenInfoNet472Wrapper(bytes); +#else + iRfc3161TimestampTokenInfo = new Rfc3161TimestampTokenInfoNetstandard21Wrapper(bytes); +#endif + return iRfc3161TimestampTokenInfo; +#else + throw new NotSupportedException(); +#endif + } + } +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoNet472Wrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoNet472Wrapper.cs new file mode 100644 index 00000000000..9bdb1a6c47d --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoNet472Wrapper.cs @@ -0,0 +1,43 @@ +// 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; +using System.Security.Cryptography; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_DESKTOP + internal sealed class Rfc3161TimestampTokenInfoNet472Wrapper : IRfc3161TimestampTokenInfo + { + private Rfc3161TimestampTokenInfo _rfc3161TimestampTokenInfo; + + public Rfc3161TimestampTokenInfoNet472Wrapper(byte[] timestampTokenInfo) + { + _rfc3161TimestampTokenInfo = new Rfc3161TimestampTokenInfo(timestampTokenInfo); + } + + public Rfc3161TimestampTokenInfoNet472Wrapper(Rfc3161TimestampTokenInfo timestampTokenInfo) + { + _rfc3161TimestampTokenInfo = timestampTokenInfo; + } + + public string PolicyId => _rfc3161TimestampTokenInfo.PolicyId; + + public DateTimeOffset Timestamp => _rfc3161TimestampTokenInfo.Timestamp; + + public long? AccuracyInMicroseconds => _rfc3161TimestampTokenInfo.AccuracyInMicroseconds; + + public Oid HashAlgorithmId => _rfc3161TimestampTokenInfo.HashAlgorithmId; + + public bool HasMessageHash(byte[] hash) + { + return _rfc3161TimestampTokenInfo.HasMessageHash(hash); + } + + public byte[] GetNonce() + { + return _rfc3161TimestampTokenInfo.GetNonce(); + } + } +#endif +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoNetstandard21Wrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoNetstandard21Wrapper.cs new file mode 100644 index 00000000000..cedd8fc2f91 --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenInfoNetstandard21Wrapper.cs @@ -0,0 +1,69 @@ +// 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; +using System.Linq; +using System.Security.Cryptography; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_CORECLR + internal sealed class Rfc3161TimestampTokenInfoNetstandard21Wrapper : IRfc3161TimestampTokenInfo + { + private System.Security.Cryptography.Pkcs.Rfc3161TimestampTokenInfo _rfc3161TimestampTokenInfo; + + public Rfc3161TimestampTokenInfoNetstandard21Wrapper(byte[] timestampTokenInfo) + { + bool success = System.Security.Cryptography.Pkcs.Rfc3161TimestampTokenInfo.TryDecode( + new ReadOnlyMemory(timestampTokenInfo), + out _rfc3161TimestampTokenInfo, + out var _); + + if (!success) + { + throw new CryptographicException(Strings.InvalidAsn1); + } + } + + public Rfc3161TimestampTokenInfoNetstandard21Wrapper(System.Security.Cryptography.Pkcs.Rfc3161TimestampTokenInfo timestampTokenInfo) + { + _rfc3161TimestampTokenInfo = timestampTokenInfo; + } + + public string PolicyId => _rfc3161TimestampTokenInfo.PolicyId.ToString(); + + public DateTimeOffset Timestamp => _rfc3161TimestampTokenInfo.Timestamp; + + public long? AccuracyInMicroseconds => _rfc3161TimestampTokenInfo.AccuracyInMicroseconds; + + public Oid HashAlgorithmId => _rfc3161TimestampTokenInfo.HashAlgorithmId; + + public bool HasMessageHash(byte[] hash) + { + if (hash == null) + { + return false; + } + + var value = _rfc3161TimestampTokenInfo.GetMessageHash().ToArray(); + + if (hash.Length != value.Length) + { + return false; + } + + return value.SequenceEqual(hash); + } + + public byte[] GetNonce() + { + ReadOnlyMemory? nonce = _rfc3161TimestampTokenInfo.GetNonce(); + if (nonce.HasValue) + { + return nonce.Value.ToArray(); + } + return Array.Empty(); + } + } +#endif +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenNet472Wrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenNet472Wrapper.cs new file mode 100644 index 00000000000..39178d7d06d --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenNet472Wrapper.cs @@ -0,0 +1,36 @@ +// 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.Pkcs; +using System.Security.Cryptography.X509Certificates; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_DESKTOP + internal sealed class Rfc3161TimestampTokenNet472Wrapper : IRfc3161TimestampToken + { + private readonly Rfc3161TimestampToken _rfc3161TimestampToken; + + public Rfc3161TimestampTokenNet472Wrapper( + IRfc3161TimestampTokenInfo tstInfo, + X509Certificate2 signerCertificate, + X509Certificate2Collection additionalCerts, + byte[] encoded) + { + _rfc3161TimestampToken = new Rfc3161TimestampToken( + tstInfo, + signerCertificate, + additionalCerts, + encoded); + } + + public IRfc3161TimestampTokenInfo TokenInfo => _rfc3161TimestampToken.TokenInfo; + + public SignedCms AsSignedCms() + { + return _rfc3161TimestampToken.AsSignedCms(); + } + } +#endif +} + diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenNetstandard21Wrapper.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenNetstandard21Wrapper.cs new file mode 100644 index 00000000000..7b017e6336b --- /dev/null +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampTokenNetstandard21Wrapper.cs @@ -0,0 +1,51 @@ +// 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; +using System.Security.Cryptography; +using System.Security.Cryptography.Pkcs; +using System.Security.Cryptography.X509Certificates; + +namespace NuGet.Packaging.Signing +{ +#if IS_SIGNING_SUPPORTED && IS_CORECLR + internal sealed class Rfc3161TimestampTokenNetstandard21Wrapper : IRfc3161TimestampToken + { + private readonly System.Security.Cryptography.Pkcs.Rfc3161TimestampToken _rfc3161TimestampToken; + public IRfc3161TimestampTokenInfo TokenInfo { get; } + + public Rfc3161TimestampTokenNetstandard21Wrapper( + IRfc3161TimestampTokenInfo tstInfo, + X509Certificate2 signerCertificate, + X509Certificate2Collection additionalCerts, + byte[] encoded) + { + bool success = System.Security.Cryptography.Pkcs.Rfc3161TimestampToken.TryDecode( + new ReadOnlyMemory(encoded), + out _rfc3161TimestampToken, + out var _); + + if (!success) + { + throw new CryptographicException(Strings.InvalidAsn1); + } + + TokenInfo = new Rfc3161TimestampTokenInfoNetstandard21Wrapper(_rfc3161TimestampToken.TokenInfo); + } + + public Rfc3161TimestampTokenNetstandard21Wrapper( + System.Security.Cryptography.Pkcs.Rfc3161TimestampToken rfc3161TimestampToken) + { + _rfc3161TimestampToken = rfc3161TimestampToken; + + TokenInfo = new Rfc3161TimestampTokenInfoNetstandard21Wrapper(_rfc3161TimestampToken.TokenInfo); + } + + public SignedCms AsSignedCms() + { + return _rfc3161TimestampToken.AsSignedCms(); + } + } +#endif +} + diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampVerificationUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampVerificationUtility.cs index 44217fb01e5..46a63c47775 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampVerificationUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Rfc3161TimestampVerificationUtility.cs @@ -4,7 +4,7 @@ using System; using System.IO; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif @@ -19,7 +19,7 @@ internal static class Rfc3161TimestampVerificationUtility { private const double _millisecondsPerMicrosecond = 0.001; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED internal static bool ValidateSignerCertificateAgainstTimestamp( X509Certificate2 signerCertificate, @@ -34,19 +34,19 @@ internal static bool ValidateSignerCertificateAgainstTimestamp( internal static bool TryReadTSTInfoFromSignedCms( SignedCms timestampCms, - out Rfc3161TimestampTokenInfo tstInfo) + out IRfc3161TimestampTokenInfo tstInfo) { tstInfo = null; if (timestampCms.ContentInfo.ContentType.Value.Equals(Oids.TSTInfoContentType)) { - tstInfo = new Rfc3161TimestampTokenInfo(timestampCms.ContentInfo.Content); + tstInfo = Rfc3161TimestampTokenInfoFactory.Create(timestampCms.ContentInfo.Content); return true; } // return false if the signedCms object does not contain the right ContentType return false; } - internal static double GetAccuracyInMilliseconds(Rfc3161TimestampTokenInfo tstInfo) + internal static double GetAccuracyInMilliseconds(IRfc3161TimestampTokenInfo tstInfo) { double accuracyInMilliseconds; diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Timestamp.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Timestamp.cs index 2fcccda9225..d2b9857995e 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Timestamp.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Timestamp.cs @@ -8,7 +8,7 @@ using System.Security.Cryptography.X509Certificates; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif @@ -16,7 +16,7 @@ namespace NuGet.Packaging.Signing { public sealed class Timestamp { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Upper limit of Timestamp. @@ -46,7 +46,7 @@ public sealed class Timestamp /// /// Timestamp token info for this timestamp. /// - internal Rfc3161TimestampTokenInfo TstInfo { get; } + internal IRfc3161TimestampTokenInfo TstInfo { get; } /// /// Default constructor. Limits are set to current time. @@ -273,4 +273,4 @@ internal SignatureVerificationStatusFlags Verify( } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/AttributeUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/AttributeUtility.cs index eeac36e7532..d9e2f9a8ff6 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/AttributeUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/AttributeUtility.cs @@ -6,7 +6,7 @@ using System.Globalization; using System.Linq; using System.Security.Cryptography; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using System.Security.Cryptography.X509Certificates; @@ -15,7 +15,7 @@ namespace NuGet.Packaging.Signing { public static class AttributeUtility { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Create a CommitmentTypeIndication attribute. /// https://tools.ietf.org/html/rfc5126.html#section-5.11.1 @@ -394,4 +394,4 @@ public static IEnumerable GetAttributes(this Crypt } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SignatureUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SignatureUtility.cs index 99539a0893e..bb82ef9b000 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SignatureUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SignatureUtility.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.Linq; using System.Security.Cryptography; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using System.Security.Cryptography.X509Certificates; @@ -23,7 +23,7 @@ private enum SigningCertificateRequirement EitherOrBoth } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Gets certificates in the certificate chain for the primary signature. /// @@ -680,4 +680,4 @@ internal Errors( } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SigningUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SigningUtility.cs index 564231babe4..a23f18de80c 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SigningUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/SigningUtility.cs @@ -6,7 +6,7 @@ using System.Globalization; using System.IO; using System.Security.Cryptography; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using System.Security.Cryptography.X509Certificates; @@ -56,7 +56,7 @@ public static void Verify(SignPackageRequest request, ILogger logger) request.BuildSigningCertificateChainOnce(logger); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public static CryptographicAttributeObjectCollection CreateSignedAttributes( SignPackageRequest request, IReadOnlyList chainList) @@ -293,4 +293,4 @@ private static SignatureContent GenerateSignatureContent(Common.HashAlgorithmNam public static Task SignAsync(SigningOptions options, SignPackageRequest signRequest, CancellationToken token) => throw new NotImplementedException(); #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/VerificationUtility.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/VerificationUtility.cs index 40ef762d94a..8f96ca0f974 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Utility/VerificationUtility.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Utility/VerificationUtility.cs @@ -95,7 +95,7 @@ internal static SignatureVerificationStatusFlags ValidateSigningCertificate(X509 return validationFlags; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED internal static SignatureVerificationStatusFlags ValidateTimestamp(Timestamp timestamp, Signature signature, bool treatIssuesAsErrors, List issues, SigningSpecifications spec) { if (timestamp == null) @@ -189,4 +189,4 @@ internal static SignatureVerificationStatusFlags ValidateTimestamp(Timestamp tim } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Verification/AllowListVerificationProvider.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Verification/AllowListVerificationProvider.cs index 056bc0a88e3..1bf728c7a9a 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Verification/AllowListVerificationProvider.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Verification/AllowListVerificationProvider.cs @@ -31,7 +31,7 @@ public Task GetTrustResultAsync(ISignedPackageReader return Task.FromResult(VerifyAllowList(package, signature, settings)); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private PackageVerificationResult VerifyAllowList(ISignedPackageReader package, PrimarySignature signature, SignedPackageVerifierSettings settings) { var treatIssuesAsErrors = !settings.AllowUntrusted; diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Verification/IntegrityVerificationProvider.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Verification/IntegrityVerificationProvider.cs index 09c928521db..a851abc39af 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Verification/IntegrityVerificationProvider.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Verification/IntegrityVerificationProvider.cs @@ -18,7 +18,7 @@ public Task GetTrustResultAsync(ISignedPackageReader return VerifyPackageIntegrityAsync(package, signature, settings); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private async Task VerifyPackageIntegrityAsync(ISignedPackageReader package, PrimarySignature signature, SignedPackageVerifierSettings settings) { var status = SignatureVerificationStatus.Unknown; @@ -57,4 +57,4 @@ private Task VerifyPackageIntegrityAsync(ISignedPacka } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/Verification/SignatureTrustAndValidityVerificationProvider.cs b/src/NuGet.Core/NuGet.Packaging/Signing/Verification/SignatureTrustAndValidityVerificationProvider.cs index c5191a976c7..4b9c6e32c6c 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/Verification/SignatureTrustAndValidityVerificationProvider.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/Verification/SignatureTrustAndValidityVerificationProvider.cs @@ -51,7 +51,7 @@ public Task GetTrustResultAsync( return Task.FromResult(result); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private PackageVerificationResult Verify( PrimarySignature signature, SignedPackageVerifierSettings settings) @@ -292,4 +292,4 @@ private PackageVerificationResult Verify( } #endif } -} \ No newline at end of file +} diff --git a/src/NuGet.Core/NuGet.Packaging/Strings.Designer.cs b/src/NuGet.Core/NuGet.Packaging/Strings.Designer.cs index e28f583bc06..d460ca5bf9b 100644 --- a/src/NuGet.Core/NuGet.Packaging/Strings.Designer.cs +++ b/src/NuGet.Core/NuGet.Packaging/Strings.Designer.cs @@ -60,6 +60,15 @@ internal Strings() { } } + /// + /// Looks up a localized string similar to An absolute URI is required.. + /// + internal static string AnAbsoluteUriIsRequired { + get { + return ResourceManager.GetString("AnAbsoluteUriIsRequired", resourceCulture); + } + } + /// /// Looks up a localized string similar to The argument cannot be null or empty.. /// @@ -555,6 +564,15 @@ internal static string FallbackFolderNotFound { } } + /// + /// Looks up a localized string similar to HTTP or HTTPS is required.. + /// + internal static string HttpOrHttpsIsRequired { + get { + return ResourceManager.GetString("HttpOrHttpsIsRequired", resourceCulture); + } + } + /// /// Looks up a localized string similar to The argument is invalid.. /// @@ -1572,6 +1590,24 @@ internal static string TimestampResponseExceptionGeneral { } } + /// + /// Looks up a localized string similar to The timestamp service responded with HTTP status code '{0}' ('{1}').. + /// + internal static string TimestampServiceRespondedError { + get { + return ResourceManager.GetString("TimestampServiceRespondedError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The reply from the timestamp server was invalid.. + /// + internal static string TimestampServiceRespondedInvalidFormat { + get { + return ResourceManager.GetString("TimestampServiceRespondedInvalidFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to The timestamp signature has an unsupported digest algorithm ({0}). The following algorithms are supported: {1}.. /// diff --git a/src/NuGet.Core/NuGet.Packaging/Strings.resx b/src/NuGet.Core/NuGet.Packaging/Strings.resx index fd2eaed6bd6..a21c87ff1c8 100644 --- a/src/NuGet.Core/NuGet.Packaging/Strings.resx +++ b/src/NuGet.Core/NuGet.Packaging/Strings.resx @@ -829,4 +829,17 @@ Valid from: Path: {0} 0 - folder path + + An absolute URI is required. + + + HTTP or HTTPS is required. + + + The timestamp service responded with HTTP status code '{0}' ('{1}'). + {0} is the httpResponse.StatusCode, {1} is the httpResponse.ReasonPhrase. + + + The reply from the timestamp server was invalid. + diff --git a/src/NuGet.Core/NuGet.ProjectModel/NuGet.ProjectModel.csproj b/src/NuGet.Core/NuGet.ProjectModel/NuGet.ProjectModel.csproj index 0515216cfc2..d452115ccca 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/NuGet.ProjectModel.csproj +++ b/src/NuGet.Core/NuGet.ProjectModel/NuGet.ProjectModel.csproj @@ -1,4 +1,8 @@ + + true + + @@ -22,7 +26,7 @@ - + diff --git a/src/NuGet.Core/NuGet.Protocol/NuGet.Protocol.csproj b/src/NuGet.Core/NuGet.Protocol/NuGet.Protocol.csproj index 7f08b3da644..c3d3c399b4e 100644 --- a/src/NuGet.Core/NuGet.Protocol/NuGet.Protocol.csproj +++ b/src/NuGet.Core/NuGet.Protocol/NuGet.Protocol.csproj @@ -1,4 +1,8 @@ + + true + + @@ -46,7 +50,7 @@ - + diff --git a/src/NuGet.Core/NuGet.Resolver/NuGet.Resolver.csproj b/src/NuGet.Core/NuGet.Resolver/NuGet.Resolver.csproj index 9874ca1f6bf..09d75f97877 100644 --- a/src/NuGet.Core/NuGet.Resolver/NuGet.Resolver.csproj +++ b/src/NuGet.Core/NuGet.Resolver/NuGet.Resolver.csproj @@ -1,4 +1,8 @@ + + true + + diff --git a/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/Commands/SignCommandTestFixture.cs b/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/Commands/SignCommandTestFixture.cs index dedefadcf36..6202c3d5cc7 100644 --- a/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/Commands/SignCommandTestFixture.cs +++ b/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/Commands/SignCommandTestFixture.cs @@ -55,7 +55,7 @@ public TrustedTestCert TrustedTestCertificate // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - _trustedTestCert = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root, StoreLocation.LocalMachine); + _trustedTestCert = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root); } return _trustedTestCert; @@ -72,7 +72,7 @@ public TrustedTestCert TrustedTestCertificateWithInvalidEku // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - _trustedTestCertWithInvalidEku = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root, StoreLocation.LocalMachine); + _trustedTestCertWithInvalidEku = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root); } return _trustedTestCertWithInvalidEku; @@ -90,7 +90,7 @@ public TrustedTestCert TrustedTestCertificateExpired // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - _trustedTestCertExpired = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root, StoreLocation.LocalMachine); + _trustedTestCertExpired = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root); } return _trustedTestCertExpired; @@ -108,7 +108,7 @@ public TrustedTestCert TrustedTestCertificateNotYetValid // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - _trustedTestCertNotYetValid = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root, StoreLocation.LocalMachine); + _trustedTestCertNotYetValid = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root); } return _trustedTestCertNotYetValid; @@ -394,4 +394,4 @@ private async Task CreateDefaultTrustedTimestampServiceAsync() return timestampService; } } -} \ No newline at end of file +} diff --git a/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/MSSignCommandTestFixture.cs b/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/MSSignCommandTestFixture.cs index 25ae64e800b..870b04e1a3d 100644 --- a/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/MSSignCommandTestFixture.cs +++ b/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/MSSignCommandTestFixture.cs @@ -6,7 +6,6 @@ using System.IO; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; -using NuGet.CommandLine.Test; using Test.Utility.Signing; namespace NuGet.MSSigning.Extensions.FuncTest.Commands @@ -46,7 +45,7 @@ public TrustedTestCert TrustedTestCertificateWithPrivateKey // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - _trustedTestCertWithPrivateKey = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root, StoreLocation.LocalMachine); + _trustedTestCertWithPrivateKey = TestCertificate.Generate(actionGenerator).WithPrivateKeyAndTrust(StoreName.Root); } return _trustedTestCertWithPrivateKey; @@ -64,7 +63,7 @@ public TrustedTestCert TrustedTestCertificateWithoutPrivateKey // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - _trustedTestCertWithoutPrivateKey = TestCertificate.Generate(actionGenerator).WithTrust(StoreName.Root, StoreLocation.LocalMachine); + _trustedTestCertWithoutPrivateKey = TestCertificate.Generate(actionGenerator).WithTrust(); } return _trustedTestCertWithoutPrivateKey; @@ -102,11 +101,12 @@ private async Task CreateDefaultTrustedCertificateAuthorit var rootCa = CertificateAuthority.Create(testServer.Url); var intermediateCa = rootCa.CreateIntermediateCertificateAuthority(); var rootCertificate = new X509Certificate2(rootCa.Certificate.GetEncoded()); + StoreLocation storeLocation = CertificateStoreUtilities.GetTrustedCertificateStoreLocation(); _trustedTimestampRoot = TrustedTestCert.Create( rootCertificate, StoreName.Root, - StoreLocation.LocalMachine); + storeLocation); var ca = intermediateCa; diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreNETCoreTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreNETCoreTest.cs index e1866a7ea93..f6806aff1e9 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreNETCoreTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreNETCoreTest.cs @@ -6775,6 +6775,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -6829,6 +6831,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -6898,6 +6902,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( xml.Save(projectA.ProjectPath); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -6958,6 +6964,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -7023,6 +7031,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -7136,6 +7146,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + var r = Util.RestoreSolution(pathContext); // Preconditions @@ -7153,6 +7165,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( Assert.False(Directory.Exists(packagePath), $"{packageX.ToString()} should not be installed anymore."); + // Act r = Util.RestoreSolution(pathContext); Assert.True(r.Success, r.AllOutput); @@ -7193,6 +7206,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + var r = Util.RestoreSolution(pathContext); // Preconditions @@ -7207,6 +7222,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( Assert.True(Directory.Exists(packagePath), $"{packageX.ToString()} is not installed"); Assert.Contains("Writing cache file", r.Item2); + // Act r = Util.RestoreSolution(pathContext); Assert.True(r.Success, r.AllOutput); @@ -7252,6 +7268,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -7316,6 +7334,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( solution.Projects.Add(projectA); solution.Create(pathContext.SolutionRoot); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -7390,6 +7410,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( xml.Save(projectB.ProjectPath); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); @@ -7481,6 +7503,8 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( xml.Save(projectA.ProjectPath); + Util.CreateTempGlobalJson(pathContext.SolutionRoot); + // Act var r = Util.RestoreSolution(pathContext); diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs index 4c0a61527f1..ddd6ca2b3b8 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Util.cs @@ -1246,5 +1246,29 @@ public static void TestCommandInvalidArguments(string command) // Verify traits of help message in stdout Assert.Contains("usage:", result.Item2); } + + //This is a temporary change since the VS on CI doesn't have the latest hostfxr, it could not resolve the preview SDK. + //Will be removed when CI has the latest version of VS, or SDK3.0 released RTM version. + //Create a global.json file in temporary testing folder, to make sure msbuild could choose preview version of SDK. + public static void CreateTempGlobalJson(string solutionRoot) + { + //put the global.json at one level up to solutionRoot path + var pathToPlaceGlobalJsonFile = solutionRoot.Substring(0, solutionRoot.Length - 1 - solutionRoot.Split(Path.DirectorySeparatorChar).Last().Length); + + var globalJsonFile = +@"{ + ""sdk"": { + ""version"": ""5.0.100-alpha1"" + } +}"; + + using (var outputFile = new StreamWriter(Path.Combine(pathToPlaceGlobalJsonFile, "global.json"))) + { + outputFile.WriteLine(globalJsonFile); + outputFile.Close(); + } + + } + } } diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/Dotnet.Integration.Test.csproj b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/Dotnet.Integration.Test.csproj index 0651fac5d73..62dd434cd28 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/Dotnet.Integration.Test.csproj +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/Dotnet.Integration.Test.csproj @@ -1,13 +1,18 @@ - + + + true + true + + - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true Integration tests for NuGet-powered dotnet CLI commands such as pack/restore/list package and dotnet nuget. - + @@ -22,7 +27,6 @@ - diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetRestoreTests.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetRestoreTests.cs index 852c7e02e38..e5c180abedd 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetRestoreTests.cs +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetRestoreTests.cs @@ -230,7 +230,6 @@ public async Task DotnetRestore_ProjectMovedDoesNotRunRestore() ProjectFileUtils.SetTargetFrameworkForProject(xml, "TargetFrameworks", tfm); var attributes = new Dictionary() { { "Version", "1.0.0" } }; - ProjectFileUtils.AddItem( xml, "PackageReference", diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs index 17186bfb9c4..17124d115f3 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs @@ -6,9 +6,13 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; +using System.Text; using System.Threading; +using Newtonsoft.Json.Linq; using NuGet.Common; using NuGet.Packaging.Core; +using NuGet.Protocol; using NuGet.Test.Utility; using NuGet.XPlat.FuncTest; using Xunit; @@ -29,9 +33,18 @@ public MsbuildIntegrationTestFixture() _cliDirectory = CopyLatestCliForPack(); var dotnetExecutableName = RuntimeEnvironmentHelper.IsWindows ? "dotnet.exe" : "dotnet"; TestDotnetCli = Path.Combine(_cliDirectory, dotnetExecutableName); - MsBuildSdksPath = Path.Combine(Directory.GetDirectories - (Path.Combine(_cliDirectory, "sdk")) - .First(), "Sdks"); + + var sdkPaths = Directory.GetDirectories(Path.Combine(_cliDirectory, "sdk")); + + // TODO - remove when shipping. See https://github.com/NuGet/Home/issues/8508 + // const string dotnetMajorVersion = "3."; + const string dotnetMajorVersion = "5."; + PatchSDKWithCryptographyDlls(dotnetMajorVersion, sdkPaths); + + MsBuildSdksPath = Path.Combine( + sdkPaths.Where(path => path.Split(Path.DirectorySeparatorChar).Last().StartsWith(dotnetMajorVersion)).First() + , "Sdks"); + _templateDirectory = TestDirectory.Create(); _processEnvVars.Add("MSBuildSDKsPath", MsBuildSdksPath); @@ -75,7 +88,7 @@ internal void CreateDotnetNewProject(string solutionRoot, string projectName, st private static void CopyFromTemplate(string projectName, string args, string workingDirectory, DirectoryInfo templateDirectoryInfo) { - foreach(var file in templateDirectoryInfo.GetFiles()) + foreach (var file in templateDirectoryInfo.GetFiles()) { File.Copy(file.FullName, Path.Combine(workingDirectory, file.Name)); } @@ -98,7 +111,8 @@ internal void CreateDotnetToolProject(string solutionRoot, string projectName, s var restoreSolutionDirectory = workingDirectory; var msbuildProjectExtensionsPath = Path.Combine(workingDirectory); var packageReference = string.Empty; - foreach (var package in packages) { + foreach (var package in packages) + { packageReference = string.Concat(packageReference, Environment.NewLine, $@""); } @@ -170,7 +184,7 @@ private void RestoreProjectOrSolution(string workingDirectory, string fileName, /// /// dotnet.exe args /// - internal CommandRunnerResult RunDotnet(string workingDirectory, string args, bool ignoreExitCode=false) + internal CommandRunnerResult RunDotnet(string workingDirectory, string args, bool ignoreExitCode = false) { var result = CommandRunner.Run(TestDotnetCli, workingDirectory, @@ -280,24 +294,28 @@ private void CopyRestoreArtifacts(string artifactsDirectory, string pathToSdkInC foreach (var projectName in sdkDependencies) { var projectArtifactsFolder = new DirectoryInfo(Path.Combine(artifactsDirectory, projectName, toolsetVersion, "bin", configuration)); - foreach (var frameworkArtifactsFolder in projectArtifactsFolder.EnumerateDirectories()) + + IEnumerable frameworkArtifactFolders = projectArtifactsFolder.EnumerateDirectories().Where(folder => folder.FullName.Contains("netstandard2.1") || folder.FullName.Contains("netcoreapp5.0")); + + if (!frameworkArtifactFolders.Any()) + { + frameworkArtifactFolders = projectArtifactsFolder.EnumerateDirectories().Where(folder => folder.FullName.Contains("netstandard2.0")); + } + + foreach (var frameworkArtifactsFolder in frameworkArtifactFolders) { - if (frameworkArtifactsFolder.FullName.Contains("netstandard") || - frameworkArtifactsFolder.FullName.Contains("netcoreapp")) + var fileName = projectName + ".dll"; + File.Copy( + sourceFileName: Path.Combine(frameworkArtifactsFolder.FullName, fileName), + destFileName: Path.Combine(pathToSdkInCli, fileName), + overwrite: true); + // Copy the restore targets. + if (projectName.Equals(restoreProjectName)) { - var fileName = projectName + ".dll"; File.Copy( - sourceFileName: Path.Combine(frameworkArtifactsFolder.FullName, fileName), - destFileName: Path.Combine(pathToSdkInCli, fileName), - overwrite: true); - // Copy the restore targets. - if (projectName.Equals(restoreProjectName)) - { - File.Copy( - sourceFileName: Path.Combine(frameworkArtifactsFolder.FullName, restoreTargetsName), - destFileName: Path.Combine(pathToSdkInCli, restoreTargetsName), - overwrite: true); - } + sourceFileName: Path.Combine(frameworkArtifactsFolder.FullName, restoreTargetsName), + destFileName: Path.Combine(pathToSdkInCli, restoreTargetsName), + overwrite: true); } } } @@ -310,7 +328,8 @@ private void CopyPackSdkArtifacts(string artifactsDirectory, string pathToSdkInC const string packProjectName = "NuGet.Build.Tasks.Pack"; const string packTargetsName = "NuGet.Build.Tasks.Pack.targets"; // Copy the pack SDK. - var packProjectCoreArtifactsDirectory = new DirectoryInfo(Path.Combine(artifactsDirectory, packProjectName, toolsetVersion, "bin", configuration)).EnumerateDirectories("netstandard*").Single(); + //Order by fullname so that we can get the latest nestandard version. E.g. if we have both netstandard2.0 and netstandard2.1, netstandard2.1 will be selected. + var packProjectCoreArtifactsDirectory = new DirectoryInfo(Path.Combine(artifactsDirectory, packProjectName, toolsetVersion, "bin", configuration)).EnumerateDirectories("netstandard*").OrderBy(x => x.FullName).Last(); var packAssemblyDestinationDirectory = Path.Combine(pathToPackSdk, "CoreCLR"); // Be smart here so we don't have to call ILMerge in the VS build. It takes ~15s total. // In VisualStudio, simply use the non il merged version. @@ -410,7 +429,7 @@ private static void DeleteDirectory(string path) for (var i = 0; i < MaxTries; i++) { - + try { Directory.Delete(path, recursive: true); @@ -427,5 +446,111 @@ private static void DeleteDirectory(string path) } } + + // Temporary added methods for processing deps.json files for patching + + /// + /// Temporary patching process to bring in Cryptography DLLs for testing while SDK gets around to including them in 5.0. + /// See also: https://github.com/NuGet/Home/issues/8508 + /// + private void PatchSDKWithCryptographyDlls(string dotnetMajorVersion, string[] sdkPaths) + { + string directoryToPatch = sdkPaths.Where(path => path.Split(Path.DirectorySeparatorChar).Last().StartsWith(dotnetMajorVersion)).First(); + var assemblyNames = new string[1] { "System.Security.Cryptography.Pkcs.dll" }; + PatchDepsJsonFiles(assemblyNames, directoryToPatch); + + string userProfilePath = Environment.GetEnvironmentVariable(RuntimeEnvironmentHelper.IsWindows ? "USERPROFILE" : "HOME"); + string globalPackagesPath = Path.Combine(userProfilePath, ".nuget", "packages"); + + CopyNewlyAddedDlls(assemblyNames, Directory.GetCurrentDirectory(), directoryToPatch); + } + + private void PatchDepsJsonFiles(string[] assemblyNames, string patchDir) + { + string[] fileNames = new string[3] { "dotnet.deps.json", "MSBuild.deps.json", "NuGet.CommandLine.XPlat.deps.json" }; + string[] fullNames = fileNames.Select(filename => Path.Combine(patchDir, filename)).ToArray(); + PatchDepsJsonWithNewlyAddedDlls(assemblyNames, fullNames); + } + + private void CopyNewlyAddedDlls(string[] assemblyNames, string copyFromPath, string copyToPath) + { + foreach (var assemblyName in assemblyNames) + { + File.Copy( + Path.Combine(copyFromPath, assemblyName), + Path.Combine(copyToPath, assemblyName) + ); + } + } + + private void PatchDepsJsonWithNewlyAddedDlls(string[] assemblyNames, string[] filePaths) + { + string nugetBuildTasksName = "NuGet.Build.Tasks/5.3.0-rtm.6251"; + foreach (string assemblyName in assemblyNames) + { + foreach (string filePath in filePaths) + { + JObject jsonFile = GetJson(filePath); + + JObject targets = jsonFile.GetJObjectProperty("targets"); + + JObject netcoreapp50 = targets.GetJObjectProperty(".NETCoreApp,Version=v5.0"); + + JObject nugetBuildTasks = netcoreapp50.GetJObjectProperty(nugetBuildTasksName); + + JObject runtime = nugetBuildTasks.GetJObjectProperty("runtime"); + + var assemblyPath = Path.Combine(Directory.GetCurrentDirectory(), assemblyName); + var assemblyVersion = Assembly.LoadFile(assemblyPath).GetName().Version.ToString(); + var assemblyFileVersion = FileVersionInfo.GetVersionInfo(assemblyPath).FileVersion; + var jproperty = new JProperty("lib/netstandard2.1/" + assemblyName, + new JObject + { + new JProperty("assemblyVersion", assemblyVersion), + new JProperty("fileVersion", assemblyFileVersion), + } + ); + runtime.Add(jproperty); + nugetBuildTasks["runtime"] = runtime; + netcoreapp50[nugetBuildTasksName] = nugetBuildTasks; + targets[".NETCoreApp,Version=v5.0"] = netcoreapp50; + jsonFile["targets"] = targets; + SaveJson(jsonFile, filePath); + } + } + } + + private JObject GetJson(string jsonFilePath) + { + try + { + return FileUtility.SafeRead(jsonFilePath, (stream, filePath) => + { + using (var reader = new StreamReader(stream)) + { + return JObject.Parse(reader.ReadToEnd()); + } + }); + } + catch (Exception ex) + { + throw new InvalidOperationException( + string.Format("Failed to read json file at {0}: {1}", jsonFilePath, ex.Message), + ex + ); + } + } + + private void SaveJson(JObject json, string jsonFilePath) + { + FileUtility.Replace((outputPath) => + { + using (var writer = new StreamWriter(outputPath, append: false, encoding: Encoding.UTF8)) + { + writer.Write(json.ToString()); + } + }, + jsonFilePath); + } } } diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs index 16ff99052d8..5bf196d9920 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs @@ -16,6 +16,8 @@ using NuGet.Test.Utility; using NuGet.Versioning; using Xunit; +using NuGet.XPlat.FuncTest; + namespace Dotnet.Integration.Test @@ -616,6 +618,7 @@ public void PackCommand_PackProject_AddsProjectRefsAsPackageRefs() Assert.Equal(framework, dependencyGroups[0].TargetFramework); + var packagesA = dependencyGroups[0].Packages.ToList(); Assert.Equal(1, packagesA.Count); @@ -4047,7 +4050,7 @@ public void PackCommand_PackProject_PacksFrameworkReferences(string frameworkRef } ProjectFileUtils.SetTargetFrameworkForProject(xml, frameworkProperty, targetFrameworks); - foreach(var frameworkRef in frameworkReftoPack) + foreach (var frameworkRef in frameworkReftoPack) { var attributes = new Dictionary(); @@ -4464,4 +4467,5 @@ public void PackCommand_DoesNotGenerateOwnersElement() } } } + } diff --git a/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/NuGet.Commands.FuncTest.csproj b/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/NuGet.Commands.FuncTest.csproj index 9fde40b1991..598d2774a06 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/NuGet.Commands.FuncTest.csproj +++ b/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/NuGet.Commands.FuncTest.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true functional Integration tests for the more involved NuGet.Commands, such as restore. diff --git a/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs b/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs index 9953d71fead..0b099cef719 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs @@ -1857,8 +1857,6 @@ public async Task RestoreCommand_LockedLockFileWithOutOfDateProjectAsync() } } -#if IS_DESKTOP - // TODO: To work on coreclr we need to address https://github.com/NuGet/Home/issues/7588 [Fact] public void RestoreCommand_PathTooLongException() { @@ -1868,9 +1866,9 @@ public void RestoreCommand_PathTooLongException() new PackageSource(NuGetConstants.V3FeedUrl) }; - using(var packagesDir = TestDirectory.Create()) - using(var projectDir = TestDirectory.Create()) - using(var cacheContext = new SourceCacheContext()) + using (var packagesDir = TestDirectory.Create()) + using (var projectDir = TestDirectory.Create()) + using (var cacheContext = new SourceCacheContext()) { var configJson = JObject.Parse(@" { @@ -1886,7 +1884,18 @@ public void RestoreCommand_PathTooLongException() var spec = JsonPackageSpecReader.GetPackageSpec(configJson.ToString(), "TestProject", specPath); var logger = new TestLogger(); - var request = new TestRestoreRequest(spec, sources, packagesDir + new string('_', 300), cacheContext, logger) + string longPath = packagesDir + new string('_', 300); + try + { + // This test is pointless if the machine has long paths enabled. + Path.GetFullPath(longPath); + return; + } + catch (PathTooLongException) + { + } + + var request = new TestRestoreRequest(spec, sources, longPath, cacheContext, logger) { LockFilePath = Path.Combine(projectDir, "project.lock.json") }; @@ -1897,7 +1906,6 @@ public void RestoreCommand_PathTooLongException() new Func(async () => await command.ExecuteAsync()).ShouldThrow(); } } -#endif [Fact] public async Task RestoreCommand_RestoreExactVersionWithFailingSourceAsync() diff --git a/test/NuGet.Core.FuncTests/NuGet.Core.FuncTest/NuGet.Core.FuncTest.csproj b/test/NuGet.Core.FuncTests/NuGet.Core.FuncTest/NuGet.Core.FuncTest.csproj index e2ebcd2f1ff..11066ddf6d2 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Core.FuncTest/NuGet.Core.FuncTest.csproj +++ b/test/NuGet.Core.FuncTests/NuGet.Core.FuncTest/NuGet.Core.FuncTest.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Integration tests for various functionality from the src/NuGet.Core projects. @@ -19,7 +23,7 @@ - + diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/NuGet.Packaging.FuncTest.csproj b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/NuGet.Packaging.FuncTest.csproj index 9a38e298766..b1042cd539a 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/NuGet.Packaging.FuncTest.csproj +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/NuGet.Packaging.FuncTest.csproj @@ -1,10 +1,14 @@ + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Integration tests for the more involved NuGet.Packaging functionality, such as signing. diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/AllowListVerificationProviderTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/AllowListVerificationProviderTests.cs index bca9c5819d6..eb192fd6357 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/AllowListVerificationProviderTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/AllowListVerificationProviderTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; @@ -1101,4 +1101,4 @@ public static IEnumerable EmptyNullAndRequiredListCombinations() } } } -#endif \ No newline at end of file +#endif diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/ClientPolicyTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/ClientPolicyTests.cs index 0495954c5b6..07831eaa4b2 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/ClientPolicyTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/ClientPolicyTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; @@ -438,4 +438,4 @@ public enum SigningTestType } } -#endif \ No newline at end of file +#endif diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/IntegrityVerificationProviderTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/IntegrityVerificationProviderTests.cs index 10d17b0cf18..57ca391b43b 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/IntegrityVerificationProviderTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/IntegrityVerificationProviderTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; @@ -410,4 +410,4 @@ private static byte[] ReadPackageSignature(string packageFilePath) } } } -#endif \ No newline at end of file +#endif diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/PrimarySignatureTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/PrimarySignatureTests.cs index 0bb42e07580..75df83a68c7 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/PrimarySignatureTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/PrimarySignatureTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; @@ -210,4 +210,4 @@ private static byte[] ReadSignatureFile(string packageFilePath) } } } -#endif \ No newline at end of file +#endif diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/RepositoryCountersignatureTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/RepositoryCountersignatureTests.cs index b3fe0fe58b8..977bcff5b3c 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/RepositoryCountersignatureTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/RepositoryCountersignatureTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; @@ -182,4 +182,4 @@ internal static async Task CreateWithoutRepositoryCountersignatureAsync( } } } -#endif \ No newline at end of file +#endif diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTests.cs index 42f49b0084d..5fee991df73 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; @@ -59,7 +59,7 @@ public async Task Verify_WithUntrustedSelfSignedCertificateAndNotAllowUntrusted_ Assert.Equal(SignatureVerificationStatus.Disallowed, result.Status); Assert.Equal(1, result.Issues.Count(issue => issue.Level == LogLevel.Error)); - AssertUntrustedRoot(result.Issues, LogLevel.Error); + SigningTestUtility.AssertUntrustedRoot(result.Issues, LogLevel.Error); } } @@ -233,14 +233,6 @@ private static void AssertTimestampAttributeAndValueCounts( Assert.Equal(expectedValuesCount, valuesCount); } - private static void AssertUntrustedRoot(IEnumerable issues, LogLevel logLevel) - { - Assert.Contains(issues, issue => - issue.Code == NuGetLogCode.NU3018 && - issue.Level == logLevel && - issue.Message.Contains("The primary signature found a chain building issue: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.")); - } - private static SignerInformation GetFirstSignerInfo(SignerInformationStore store) { var signers = store.GetSigners(); diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs index d6136e78cee..eefc8620fd2 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs @@ -1,12 +1,13 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; @@ -22,6 +23,7 @@ using Xunit; using BcAccuracy = Org.BouncyCastle.Asn1.Tsp.Accuracy; using DotNetUtilities = Org.BouncyCastle.Security.DotNetUtilities; +using HashAlgorithmName = NuGet.Common.HashAlgorithmName; namespace NuGet.Packaging.FuncTest { @@ -144,10 +146,9 @@ public async Task VerifySignaturesAsync_ExpiredCertificateAndTimestamp_SuccessAs }; var bcCertificate = ca.IssueCertificate(issueOptions); - using (var certificate = new X509Certificate2(bcCertificate.GetEncoded())) using (var directory = TestDirectory.Create()) + using (X509Certificate2 certificate = CertificateUtilities.GetCertificateWithPrivateKey(bcCertificate, keyPair)) { - certificate.PrivateKey = DotNetUtilities.ToRSA(keyPair.Private as RsaPrivateCrtKeyParameters); var notAfter = certificate.NotAfter.ToUniversalTime(); var packageContext = new SimpleTestPackageContext(); @@ -200,11 +201,9 @@ public async Task VerifySignaturesAsync_ExpiredCertificateAndTimestampWithTooLar var bcCertificate = ca.IssueCertificate(issueOptions); using (testServer.RegisterResponder(timestampService)) - using (var certificate = new X509Certificate2(bcCertificate.GetEncoded())) using (var directory = TestDirectory.Create()) + using (X509Certificate2 certificate = CertificateUtilities.GetCertificateWithPrivateKey(bcCertificate, keyPair)) { - certificate.PrivateKey = DotNetUtilities.ToRSA(keyPair.Private as RsaPrivateCrtKeyParameters); - var packageContext = new SimpleTestPackageContext(); var signedPackagePath = await SignedArchiveTestUtility.AuthorSignPackageAsync( certificate, @@ -820,8 +819,7 @@ public async Task GetTrustResultAsync_PrimarySignatureWithUntrustedRoot_EmptyAll var status = await provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); Assert.Equal(SignatureVerificationStatus.Disallowed, status.Trust); - Assert.True(status.Issues.Where(i => i.Level == Common.LogLevel.Error) - .Any(i => i.Message.Contains(_untrustedChainCertError))); + SigningTestUtility.AssertUntrustedRoot(status.Issues, LogLevel.Error); } } @@ -858,8 +856,7 @@ public async Task GetTrustResultAsync_RepositoryCountersignatureWithUntrustedRoo var status = await provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); Assert.Equal(SignatureVerificationStatus.Disallowed, status.Trust); - Assert.True(status.Issues.Where(i => i.Level == Common.LogLevel.Error) - .Any(i => i.Message.Contains(_untrustedChainCertError))); + SigningTestUtility.AssertUntrustedRoot(status.Issues, LogLevel.Error); } } @@ -895,8 +892,7 @@ public async Task GetTrustResultAsync_PrimarySignatureWithUntrustedRoot_NotInAll var status = await provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); Assert.Equal(SignatureVerificationStatus.Disallowed, status.Trust); - Assert.True(status.Issues.Where(i => i.Level == Common.LogLevel.Error) - .Any(i => i.Message.Contains(_untrustedChainCertError))); + SigningTestUtility.AssertUntrustedRoot(status.Issues, LogLevel.Error); } } @@ -934,8 +930,7 @@ public async Task GetTrustResultAsync_RepositoryCountersignatureWithUntrustedRoo var status = await provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); Assert.Equal(SignatureVerificationStatus.Disallowed, status.Trust); - Assert.True(status.Issues.Where(i => i.Level == Common.LogLevel.Error) - .Any(i => i.Message.Contains(_untrustedChainCertError))); + SigningTestUtility.AssertUntrustedRoot(status.Issues, LogLevel.Error); } } @@ -1044,10 +1039,17 @@ public async Task GetTrustResultAsync_WithUnavailableRevocationInformationInRequ LogLevel.Warning, settings); - Assert.Equal(2, matchingIssues.Count); + if (RuntimeEnvironmentHelper.IsMacOSX) + { + Assert.Equal(1, matchingIssues.Count); + } + else + { + Assert.Equal(2, matchingIssues.Count); + SigningTestUtility.AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); + } - AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); - AssertRevocationStatusUnknown(matchingIssues, NuGetLogCode.NU3018, LogLevel.Warning); + SigningTestUtility.AssertRevocationStatusUnknown(matchingIssues, LogLevel.Warning, NuGetLogCode.NU3018); } [CIOnlyFact] @@ -1060,10 +1062,16 @@ public async Task GetTrustResultAsync_WithUnavailableRevocationInformationInVeri LogLevel.Warning, _verifyCommandSettings); - Assert.Equal(2, matchingIssues.Count); - - AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); - AssertRevocationStatusUnknown(matchingIssues, NuGetLogCode.NU3018, LogLevel.Warning); + if (RuntimeEnvironmentHelper.IsMacOSX) + { + Assert.Equal(1, matchingIssues.Count); + } + else + { + Assert.Equal(2, matchingIssues.Count); + SigningTestUtility.AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); + } + SigningTestUtility.AssertRevocationStatusUnknown(matchingIssues, LogLevel.Warning, NuGetLogCode.NU3018); } [CIOnlyFact] @@ -1117,10 +1125,17 @@ public async Task GetTrustResultAsync_WithUnavailableRevocationInformationAndAll LogLevel.Warning, settings); - Assert.Equal(2, matchingIssues.Count); + if (RuntimeEnvironmentHelper.IsMacOSX) + { + Assert.Equal(1, matchingIssues.Count); + } + else + { + Assert.Equal(2, matchingIssues.Count); + SigningTestUtility.AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); + } - AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); - AssertRevocationStatusUnknown(matchingIssues, NuGetLogCode.NU3018, LogLevel.Warning); + SigningTestUtility.AssertRevocationStatusUnknown(matchingIssues, LogLevel.Warning, NuGetLogCode.NU3018); } [CIOnlyFact] @@ -1147,8 +1162,12 @@ public async Task GetTrustResultAsync_WithUnavailableRevocationInformationAndAll LogLevel.Information, settings); - AssertOfflineRevocationOfflineMode(matchingIssues); - AssertRevocationStatusUnknown(matchingIssues, NuGetLogCode.Undefined, LogLevel.Information); + if (!RuntimeEnvironmentHelper.IsMacOSX) + { + SigningTestUtility.AssertOfflineRevocationOfflineMode(matchingIssues); + } + + SigningTestUtility.AssertRevocationStatusUnknown(matchingIssues, LogLevel.Information, NuGetLogCode.Undefined); } [CIOnlyFact] @@ -1160,10 +1179,16 @@ public async Task GetTrustResultAsync_WithTrustedButExpiredPrimaryAndTimestampCe _verifyCommandSettings, "ExpiredPrimaryAndTimestampCertificatesWithUnavailableRevocationInfo.nupkg"); - Assert.Equal(4, matchingIssues.Count); - - AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); - AssertRevocationStatusUnknown(matchingIssues, NuGetLogCode.NU3018, LogLevel.Warning); + if (RuntimeEnvironmentHelper.IsMacOSX) + { + Assert.Equal(2, matchingIssues.Count); + } + else + { + Assert.Equal(4, matchingIssues.Count); + SigningTestUtility.AssertOfflineRevocationOnlineMode(matchingIssues, LogLevel.Warning); + } + SigningTestUtility.AssertRevocationStatusUnknown(matchingIssues, LogLevel.Warning, NuGetLogCode.NU3018); } [CIOnlyFact] @@ -1377,28 +1402,24 @@ public async Task GetTrustResultAsync_WithRevokedPrimaryCertificate_ReturnsSuspe var bcCertificate = certificateAuthority.IssueCertificate(issueCertificateOptions); var timestampService = await _fixture.GetDefaultTrustedTimestampServiceAsync(); - using (var certificate = new X509Certificate2(bcCertificate.GetEncoded())) + using (X509Certificate2 certificate = CertificateUtilities.GetCertificateWithPrivateKey(bcCertificate, issueCertificateOptions.KeyPair)) + using (var test = await Test.CreateAuthorSignedPackageAsync( + certificate, + timestampService.Url)) + using (var packageReader = new PackageArchiveReader(test.PackageFile.FullName)) { - certificate.PrivateKey = DotNetUtilities.ToRSA(issueCertificateOptions.KeyPair.Private as RsaPrivateCrtKeyParameters); - - using (var test = await Test.CreateAuthorSignedPackageAsync( - certificate, - timestampService.Url)) - using (var packageReader = new PackageArchiveReader(test.PackageFile.FullName)) - { - await certificateAuthority.OcspResponder.WaitForResponseExpirationAsync(bcCertificate); + await certificateAuthority.OcspResponder.WaitForResponseExpirationAsync(bcCertificate); - certificateAuthority.Revoke( - bcCertificate, - RevocationReason.KeyCompromise, - DateTimeOffset.UtcNow.AddHours(-1)); + certificateAuthority.Revoke( + bcCertificate, + RevocationReason.KeyCompromise, + DateTimeOffset.UtcNow.AddHours(-1)); - var primarySignature = await packageReader.GetPrimarySignatureAsync(CancellationToken.None); + var primarySignature = await packageReader.GetPrimarySignatureAsync(CancellationToken.None); - var status = await _provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); + var status = await _provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); - Assert.Equal(SignatureVerificationStatus.Suspect, status.Trust); - } + Assert.Equal(SignatureVerificationStatus.Suspect, status.Trust); } } @@ -1656,28 +1677,24 @@ public async Task GetTrustResultAsync_WithRevokedPrimaryCertificate_ReturnsSuspe var bcCertificate = certificateAuthority.IssueCertificate(issueCertificateOptions); var timestampService = await _fixture.GetDefaultTrustedTimestampServiceAsync(); - using (var certificate = new X509Certificate2(bcCertificate.GetEncoded())) + using (X509Certificate2 certificate = CertificateUtilities.GetCertificateWithPrivateKey(bcCertificate, issueCertificateOptions.KeyPair)) + using (var test = await Test.CreateRepositoryPrimarySignedPackageAsync( + certificate, + timestampService.Url)) + using (var packageReader = new PackageArchiveReader(test.PackageFile.FullName)) { - certificate.PrivateKey = DotNetUtilities.ToRSA(issueCertificateOptions.KeyPair.Private as RsaPrivateCrtKeyParameters); + await certificateAuthority.OcspResponder.WaitForResponseExpirationAsync(bcCertificate); - using (var test = await Test.CreateRepositoryPrimarySignedPackageAsync( - certificate, - timestampService.Url)) - using (var packageReader = new PackageArchiveReader(test.PackageFile.FullName)) - { - await certificateAuthority.OcspResponder.WaitForResponseExpirationAsync(bcCertificate); - - certificateAuthority.Revoke( - bcCertificate, - RevocationReason.KeyCompromise, - DateTimeOffset.UtcNow.AddHours(-1)); + certificateAuthority.Revoke( + bcCertificate, + RevocationReason.KeyCompromise, + DateTimeOffset.UtcNow.AddHours(-1)); - var primarySignature = await packageReader.GetPrimarySignatureAsync(CancellationToken.None); + var primarySignature = await packageReader.GetPrimarySignatureAsync(CancellationToken.None); - var status = await _provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); + var status = await _provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); - Assert.Equal(SignatureVerificationStatus.Suspect, status.Trust); - } + Assert.Equal(SignatureVerificationStatus.Suspect, status.Trust); } } @@ -2017,30 +2034,26 @@ public async Task VerifyAsync_WithRevokedCountersignatureCertificate_ReturnsSusp var bcCertificate = certificateAuthority.IssueCertificate(issueCertificateOptions); var timestampService = await _fixture.GetDefaultTrustedTimestampServiceAsync(); - using (var certificate = new X509Certificate2(bcCertificate.GetEncoded())) + using (X509Certificate2 certificate = CertificateUtilities.GetCertificateWithPrivateKey(bcCertificate, issueCertificateOptions.KeyPair)) + using (var test = await Test.CreateAuthorSignedRepositoryCountersignedPackageAsync( + _fixture.TrustedTestCertificate.Source.Cert, + certificate, + timestampService.Url, + timestampService.Url)) + using (var packageReader = new PackageArchiveReader(test.PackageFile.FullName)) { - certificate.PrivateKey = DotNetUtilities.ToRSA(issueCertificateOptions.KeyPair.Private as RsaPrivateCrtKeyParameters); + await certificateAuthority.OcspResponder.WaitForResponseExpirationAsync(bcCertificate); - using (var test = await Test.CreateAuthorSignedRepositoryCountersignedPackageAsync( - _fixture.TrustedTestCertificate.Source.Cert, - certificate, - timestampService.Url, - timestampService.Url)) - using (var packageReader = new PackageArchiveReader(test.PackageFile.FullName)) - { - await certificateAuthority.OcspResponder.WaitForResponseExpirationAsync(bcCertificate); - - certificateAuthority.Revoke( - bcCertificate, - RevocationReason.KeyCompromise, - DateTimeOffset.UtcNow.AddHours(-1)); + certificateAuthority.Revoke( + bcCertificate, + RevocationReason.KeyCompromise, + DateTimeOffset.UtcNow.AddHours(-1)); - var primarySignature = await packageReader.GetPrimarySignatureAsync(CancellationToken.None); + var primarySignature = await packageReader.GetPrimarySignatureAsync(CancellationToken.None); - var status = await _provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); + var status = await _provider.GetTrustResultAsync(packageReader, primarySignature, settings, CancellationToken.None); - Assert.Equal(SignatureVerificationStatus.Suspect, status.Trust); - } + Assert.Equal(SignatureVerificationStatus.Suspect, status.Trust); } } @@ -2244,30 +2257,6 @@ private static async Task> VerifyUnavailableRevocationInfoAsy } } - private static void AssertOfflineRevocationOnlineMode(IEnumerable issues, LogLevel logLevel) - { - Assert.Contains(issues, issue => - issue.Code == NuGetLogCode.NU3018 && - issue.Level == logLevel && - issue.Message.Contains("The revocation function was unable to check revocation because the revocation server could not be reached. For more information, visit https://aka.ms/certificateRevocationMode.")); - } - - private static void AssertOfflineRevocationOfflineMode(IEnumerable issues) - { - Assert.Contains(issues, issue => - issue.Code == NuGetLogCode.Undefined && - issue.Level == LogLevel.Information && - issue.Message.Contains("The revocation function was unable to check revocation because the certificate is not available in the cached certificate revocation list and NUGET_CERT_REVOCATION_MODE environment variable has been set to offline. For more information, visit https://aka.ms/certificateRevocationMode.")); - } - - private static void AssertRevocationStatusUnknown(IEnumerable issues, NuGetLogCode code, LogLevel logLevel) - { - Assert.Contains(issues, issue => - issue.Code == code && - issue.Level == logLevel && - issue.Message.Contains("The revocation function was unable to check revocation for the certificate.")); - } - private static byte[] GetResource(string name) { return ResourceTestUtility.GetResourceBytes( @@ -2301,13 +2290,14 @@ private static IDisposable TrustPrimaryTimestampRootCertificate(PrimarySignature private static IDisposable TrustRootCertificate(IX509CertificateChain certificateChain) { var rootCertificate = certificateChain.Last(); + StoreLocation storeLocation = CertificateStoreUtilities.GetTrustedCertificateStoreLocation(); return TrustedTestCert.Create( new X509Certificate2(rootCertificate), StoreName.Root, - StoreLocation.LocalMachine, + storeLocation, maximumValidityPeriod: TimeSpan.MaxValue); } } } -#endif \ No newline at end of file +#endif diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureUtilityTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureUtilityTests.cs index f4b766c9eef..93b0c6e2966 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureUtilityTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignatureUtilityTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageArchiveTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageArchiveTests.cs index d3c269140f0..d53820d567b 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageArchiveTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageArchiveTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.IO; using System.Security.Cryptography.X509Certificates; diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageIntegrityVerificationTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageIntegrityVerificationTests.cs index 8ffb8400cb2..23aa5aecee3 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageIntegrityVerificationTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SignedPackageIntegrityVerificationTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningTestFixture.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningTestFixture.cs index a0c4772830e..dda8b45b6d6 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningTestFixture.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningTestFixture.cs @@ -106,8 +106,8 @@ public IReadOnlyList> TrustedTestCertificateWit var certificate1 = SigningTestUtility.GenerateCertificate(certificateName, rsa); var certificate2 = SigningTestUtility.GenerateCertificate(certificateName, rsa); - var testCertificate1 = new TestCertificate() { Cert = certificate1 }.WithTrust(StoreName.Root, StoreLocation.LocalMachine); - var testCertificate2 = new TestCertificate() { Cert = certificate2 }.WithTrust(StoreName.Root, StoreLocation.LocalMachine); + var testCertificate1 = new TestCertificate() { Cert = certificate1 }.WithTrust(); + var testCertificate2 = new TestCertificate() { Cert = certificate2 }.WithTrust(); _trustedTestCertificateWithReissuedCertificate = new[] { @@ -197,11 +197,12 @@ private async Task CreateDefaultTrustedCertificateAuthorit var rootCa = CertificateAuthority.Create(testServer.Url); var intermediateCa = rootCa.CreateIntermediateCertificateAuthority(); var rootCertificate = new X509Certificate2(rootCa.Certificate.GetEncoded()); + StoreLocation storeLocation = CertificateStoreUtilities.GetTrustedCertificateStoreLocation(); _trustedServerRoot = TrustedTestCert.Create( rootCertificate, StoreName.Root, - StoreLocation.LocalMachine); + storeLocation); var ca = intermediateCa; @@ -250,4 +251,4 @@ public void Dispose() } } } -} \ No newline at end of file +} diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningUtilityTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningUtilityTests.cs index f01d2671592..d9f884a1b78 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningUtilityTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/SigningUtilityTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Diagnostics; diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampProviderTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampProviderTests.cs index aa667a2fd95..e7d8e6a49ed 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampProviderTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampProviderTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; @@ -24,7 +24,6 @@ namespace NuGet.Packaging.FuncTest [Collection(SigningTestCollection.Name)] public class TimestampProviderTests { - private const string ArgumentNullExceptionMessage = "Value cannot be null.\r\nParameter name: {0}"; private const string OperationCancelledExceptionMessage = "The operation was canceled."; private SigningTestFixture _testFixture; @@ -37,7 +36,7 @@ public TimestampProviderTests(SigningTestFixture fixture) } [CIOnlyFact] - public async Task GetTimestamp_WithValidInput_ReturnsTimestampAsync() + public async Task GetTimestampAsync_WithValidInput_ReturnsTimestampAsync() { var logger = new TestLogger(); var timestampService = await _testFixture.GetDefaultTrustedTimestampServiceAsync(); @@ -59,7 +58,7 @@ public async Task GetTimestamp_WithValidInput_ReturnsTimestampAsync() ); // Act - var timestampedCms = timestampProvider.GetTimestamp(request, logger, CancellationToken.None); + var timestampedCms = await timestampProvider.GetTimestampAsync(request, logger, CancellationToken.None); // Assert timestampedCms.Should().NotBeNull(); @@ -70,7 +69,7 @@ public async Task GetTimestamp_WithValidInput_ReturnsTimestampAsync() } [CIOnlyFact] - public async Task GetTimestamp_AssertCompleteChain_SuccessAsync() + public async Task GetTimestampAsync_AssertCompleteChain_SuccessAsync() { var timestampService = await _testFixture.GetDefaultTrustedTimestampServiceAsync(); var timestampProvider = new Rfc3161TimestampProvider(timestampService.Url); @@ -129,7 +128,7 @@ public async Task GetTimestamp_AssertCompleteChain_SuccessAsync() } [CIOnlyFact] - public async Task GetTimestamp_WhenRequestNull_ThrowsAsync() + public async Task GetTimestampAsync_WhenRequestNull_ThrowsAsync() { var logger = new TestLogger(); var timestampService = await _testFixture.GetDefaultTrustedTimestampServiceAsync(); @@ -157,17 +156,17 @@ public async Task GetTimestamp_WhenRequestNull_ThrowsAsync() target: SignaturePlacement.PrimarySignature ); - // Act - Action timestampAction = () => timestampProvider.GetTimestamp(null, logger, CancellationToken.None); - // Assert - timestampAction.ShouldThrow() - .WithMessage(string.Format(ArgumentNullExceptionMessage, nameof(request))); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request: null, logger, CancellationToken.None)); + + Assert.Equal("request", exception.ParamName); + Assert.StartsWith("Value cannot be null.", exception.Message); } } [CIOnlyFact] - public async Task GetTimestamp_WhenLoggerNull_ThrowsAsync() + public async Task GetTimestampAsync_WhenLoggerNull_ThrowsAsync() { var timestampService = await _testFixture.GetDefaultTrustedTimestampServiceAsync(); var timestampProvider = new Rfc3161TimestampProvider(timestampService.Url); @@ -188,17 +187,17 @@ public async Task GetTimestamp_WhenLoggerNull_ThrowsAsync() target: SignaturePlacement.PrimarySignature ); - // Act - Action timestampAction = () => timestampProvider.GetTimestamp(request, null, CancellationToken.None); - // Assert - timestampAction.ShouldThrow() - .WithMessage(string.Format(ArgumentNullExceptionMessage, "logger")); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, logger: null, CancellationToken.None)); + + Assert.Equal("logger", exception.ParamName); + Assert.StartsWith("Value cannot be null.", exception.Message); } } [CIOnlyFact] - public async Task GetTimestamp_WhenCancelled_ThrowsAsync() + public async Task GetTimestampAsync_WhenCancelled_ThrowsAsync() { var logger = new TestLogger(); var timestampService = await _testFixture.GetDefaultTrustedTimestampServiceAsync(); @@ -220,17 +219,16 @@ public async Task GetTimestamp_WhenCancelled_ThrowsAsync() target: SignaturePlacement.PrimarySignature ); - // Act - Action timestampAction = () => timestampProvider.GetTimestamp(request, logger, new CancellationToken(canceled: true)); - // Assert - timestampAction.ShouldThrow() - .WithMessage(OperationCancelledExceptionMessage); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, logger, new CancellationToken(canceled: true))); + + Assert.Equal(OperationCancelledExceptionMessage, exception.Message); } } [CIOnlyFact] - public async Task GetTimestamp_WhenRevocationInformationUnavailable_SuccessAsync() + public async Task GetTimestampAsync_WhenRevocationInformationUnavailable_SuccessAsync() { var testServer = await _testFixture.GetSigningTestServerAsync(); var ca = await _testFixture.GetDefaultTrustedCertificateAuthorityAsync(); @@ -243,10 +241,10 @@ public async Task GetTimestamp_WhenRevocationInformationUnavailable_SuccessAsync VerifyTimestampData( testServer, timestampService, - (timestampProvider, request) => + async (timestampProvider, request) => { var logger = new TestLogger(); - var timestamp = timestampProvider.GetTimestamp(request, logger, CancellationToken.None); + var timestamp = await timestampProvider.GetTimestampAsync(request, logger, CancellationToken.None); Assert.NotNull(timestamp); @@ -260,7 +258,7 @@ public async Task GetTimestamp_WhenRevocationInformationUnavailable_SuccessAsync } [CIOnlyFact] - public async Task GetTimestamp_WhenTimestampSigningCertificateRevoked_ThrowsAsync() + public async Task GetTimestampAsync_WhenTimestampSigningCertificateRevoked_ThrowsAsync() { var testServer = await _testFixture.GetSigningTestServerAsync(); var certificateAuthority = await _testFixture.GetDefaultTrustedCertificateAuthorityAsync(); @@ -274,17 +272,17 @@ public async Task GetTimestamp_WhenTimestampSigningCertificateRevoked_ThrowsAsyn VerifyTimestampData( testServer, timestampService, - (timestampProvider, request) => + async (timestampProvider, request) => { - var exception = Assert.Throws( - () => timestampProvider.GetTimestamp(request, NullLogger.Instance, CancellationToken.None)); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, NullLogger.Instance, CancellationToken.None)); Assert.Equal("Certificate chain validation failed.", exception.Message); }); } [CIOnlyFact] - public async Task GetTimestamp_WithFailureReponse_ThrowsAsync() + public async Task GetTimestampAsync_WithFailureReponse_ThrowsAsync() { var testServer = await _testFixture.GetSigningTestServerAsync(); var certificateAuthority = await _testFixture.GetDefaultTrustedCertificateAuthorityAsync(); @@ -294,10 +292,10 @@ public async Task GetTimestamp_WithFailureReponse_ThrowsAsync() VerifyTimestampData( testServer, timestampService, - (timestampProvider, request) => + async (timestampProvider, request) => { - var exception = Assert.Throws( - () => timestampProvider.GetTimestamp(request, NullLogger.Instance, CancellationToken.None)); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, NullLogger.Instance, CancellationToken.None)); Assert.StartsWith( "The timestamp signature and/or certificate could not be verified or is malformed.", @@ -306,7 +304,7 @@ public async Task GetTimestamp_WithFailureReponse_ThrowsAsync() } [CIOnlyFact] - public async Task GetTimestamp_WhenSigningCertificateNotReturned_ThrowsAsync() + public async Task GetTimestampAsync_WhenSigningCertificateNotReturned_ThrowsAsync() { var testServer = await _testFixture.GetSigningTestServerAsync(); var certificateAuthority = await _testFixture.GetDefaultTrustedCertificateAuthorityAsync(); @@ -316,17 +314,17 @@ public async Task GetTimestamp_WhenSigningCertificateNotReturned_ThrowsAsync() VerifyTimestampData( testServer, timestampService, - (timestampProvider, request) => + async (timestampProvider, request) => { - var exception = Assert.Throws( - () => timestampProvider.GetTimestamp(request, NullLogger.Instance, CancellationToken.None)); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, NullLogger.Instance, CancellationToken.None)); Assert.StartsWith("Cannot find object or property.", exception.Message); }); } [CIOnlyFact] - public async Task GetTimestamp_WhenSignatureHashAlgorithmIsSha1_ThrowsAsync() + public async Task GetTimestampAsync_WhenSignatureHashAlgorithmIsSha1_ThrowsAsync() { var testServer = await _testFixture.GetSigningTestServerAsync(); var certificateAuthority = await _testFixture.GetDefaultTrustedCertificateAuthorityAsync(); @@ -336,10 +334,10 @@ public async Task GetTimestamp_WhenSignatureHashAlgorithmIsSha1_ThrowsAsync() VerifyTimestampData( testServer, timestampService, - (timestampProvider, request) => + async (timestampProvider, request) => { - var exception = Assert.Throws( - () => timestampProvider.GetTimestamp(request, NullLogger.Instance, CancellationToken.None)); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, NullLogger.Instance, CancellationToken.None)); Assert.Equal( "The timestamp signature has an unsupported digest algorithm (SHA1). The following algorithms are supported: SHA256, SHA384, SHA512.", @@ -348,7 +346,7 @@ public async Task GetTimestamp_WhenSignatureHashAlgorithmIsSha1_ThrowsAsync() } [CIOnlyFact] - public async Task GetTimestamp_WhenCertificateSignatureAlgorithmIsSha1_ThrowsAsync() + public async Task GetTimestampAsync_WhenCertificateSignatureAlgorithmIsSha1_ThrowsAsync() { var testServer = await _testFixture.GetSigningTestServerAsync(); var certificateAuthority = await _testFixture.GetDefaultTrustedCertificateAuthorityAsync(); @@ -361,10 +359,10 @@ public async Task GetTimestamp_WhenCertificateSignatureAlgorithmIsSha1_ThrowsAsy VerifyTimestampData( testServer, timestampService, - (timestampProvider, request) => + async (timestampProvider, request) => { - var exception = Assert.Throws( - () => timestampProvider.GetTimestamp(request, NullLogger.Instance, CancellationToken.None)); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, NullLogger.Instance, CancellationToken.None)); Assert.Equal( "The timestamp certificate has an unsupported signature algorithm (SHA1RSA). The following algorithms are supported: SHA256RSA, SHA384RSA, SHA512RSA.", @@ -373,7 +371,7 @@ public async Task GetTimestamp_WhenCertificateSignatureAlgorithmIsSha1_ThrowsAsy } [CIOnlyFact] - public async Task GetTimestamp_TimestampGeneralizedTimeOutsideCertificateValidityPeriod_FailAsync() + public async Task GetTimestampAsync_TimestampGeneralizedTimeOutsideCertificateValidityPeriod_FailAsync() { // Arrange var testServer = await _testFixture.GetSigningTestServerAsync(); @@ -390,10 +388,10 @@ public async Task GetTimestamp_TimestampGeneralizedTimeOutsideCertificateValidit VerifyTimestampData( testServer, timestampService, - (timestampProvider, request) => + async (timestampProvider, request) => { - var exception = Assert.Throws( - () => timestampProvider.GetTimestamp(request, NullLogger.Instance, CancellationToken.None)); + var exception = await Assert.ThrowsAsync( + () => timestampProvider.GetTimestampAsync(request, NullLogger.Instance, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3036, exception.Code); Assert.Contains( diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampTests.cs index 97c71988c82..4f525a002bf 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TimestampTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; using System.Linq; @@ -44,10 +44,12 @@ public async Task Timestamp_Verify_WithOfflineRevocation_ReturnsCorrectFlagsAndL responders.Add(testServer.RegisterResponder(intermediateCa)); responders.Add(testServer.RegisterResponder(rootCa)); + StoreLocation storeLocation = CertificateStoreUtilities.GetTrustedCertificateStoreLocation(); + using (var trustedServerRoot = TrustedTestCert.Create( new X509Certificate2(rootCa.Certificate.GetEncoded()), StoreName.Root, - StoreLocation.LocalMachine)) + storeLocation)) { var timestampService = TimestampService.Create(intermediateCa); diff --git a/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/HttpRetryHandlerTests.cs b/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/HttpRetryHandlerTests.cs index b272a51d7e4..7298acadc3a 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/HttpRetryHandlerTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/HttpRetryHandlerTests.cs @@ -100,13 +100,17 @@ public async Task HttpRetryHandler_HandlesFailureToConnect() } else { +#if (NETCORE3_0 || NETCORE5_0) + Assert.Equal("No connection could be made because the target machine actively refused it.", exception.InnerException.Message); +#else Assert.Equal("No connection could be made because the target machine actively refused it", exception.InnerException.Message); +#endif } #else var innerException = Assert.IsType(exception.InnerException); Assert.Equal(WebExceptionStatus.ConnectFailure, innerException.Status); #endif - } + } [Fact] public async Task HttpRetryHandler_HandlesInvalidProtocol() @@ -118,7 +122,11 @@ public async Task HttpRetryHandler_HandlesInvalidProtocol() var exception = await ThrowsException(server); #if IS_CORECLR Assert.Null(exception.InnerException); +#if (NETCORE3_0 || NETCORE5_0) + Assert.Equal("Received an invalid status code: 'BAD'.", exception.Message); +#else Assert.Equal("The server returned an invalid or unrecognized response.", exception.Message); +#endif #else var innerException = Assert.IsType(exception.InnerException); Assert.Equal(WebExceptionStatus.ServerProtocolViolation, innerException.Status); @@ -138,15 +146,27 @@ public async Task HttpRetryHandler_HandlesNameResolutionFailure() if (RuntimeEnvironmentHelper.IsMacOSX) { +#if (NETCORE3_0 || NETCORE5_0) + Assert.Equal("nodename nor servname provided, or not known", exception.InnerException.Message); +#else Assert.Equal("Device not configured", exception.InnerException.Message); +#endif } else if (!RuntimeEnvironmentHelper.IsWindows) { +#if (NETCORE3_0 || NETCORE5_0) + Assert.Equal("Name or service not known", exception.InnerException.Message); +#else Assert.Equal("No such device or address", exception.InnerException.Message); +#endif } else { +#if (NETCORE3_0 || NETCORE5_0) + Assert.Equal("No such host is known.", exception.InnerException.Message); +#else Assert.Equal("No such host is known", exception.InnerException.Message); +#endif } #else var innerException = Assert.IsType(exception.InnerException); diff --git a/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/NuGet.Protocol.FuncTest.csproj b/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/NuGet.Protocol.FuncTest.csproj index 0e7ecd4a348..90a6229fc63 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/NuGet.Protocol.FuncTest.csproj +++ b/test/NuGet.Core.FuncTests/NuGet.Protocol.FuncTest/NuGet.Protocol.FuncTest.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true functional Integration tests for the more involved NuGet.Protocol functionality, such as plugins. @@ -35,7 +39,7 @@ xcopy /diye $(ArtifactsDirectory)TestablePlugin\$(BuildVariationFolder)\bin\$(Configuration)\$(TargetFramework)\win7-x64\* $(MSBuildProjectDirectory)\bin\$(Configuration)\$(TargetFramework)\win7-x64\TestablePlugin\ - + diff --git a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/DotnetCliUtil.cs b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/DotnetCliUtil.cs index 40538044785..654a7ccd94f 100644 --- a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/DotnetCliUtil.cs +++ b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/DotnetCliUtil.cs @@ -131,7 +131,7 @@ public static string GetXplatDll() var relativePaths = new string[] { - Path.Combine("artifacts", "NuGet.CommandLine.XPlat", "16.0", "bin", configuration, "netcoreapp2.1", XPlatDll) + Path.Combine("artifacts", "NuGet.CommandLine.XPlat", "16.0", "bin", configuration, "netcoreapp5.0", XPlatDll) }; foreach (var relativePath in relativePaths) diff --git a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/NuGet.XPlat.FuncTest.csproj b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/NuGet.XPlat.FuncTest.csproj index 43462b09825..0cf5717cff1 100644 --- a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/NuGet.XPlat.FuncTest.csproj +++ b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/NuGet.XPlat.FuncTest.csproj @@ -1,14 +1,20 @@  + + true + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true functional Functional tests for nuget in dotnet CLI scenarios, using the NuGet.CommandLine.XPlat assembly. + @@ -32,11 +38,11 @@ Always - + - + diff --git a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs index 4444f4ec98b..cd53f6c9a6d 100644 --- a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs @@ -344,4 +344,4 @@ public static void Locals_Success_BothFlags_HelpMessage(string args) DotnetCliUtil.VerifyResultFailure(result, expectedResult); } } -} \ No newline at end of file +} diff --git a/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Tests/Microsoft.Build.NuGetSdkResolver.Test.csproj b/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Tests/Microsoft.Build.NuGetSdkResolver.Test.csproj index 39321549808..a29696c810c 100644 --- a/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Tests/Microsoft.Build.NuGetSdkResolver.Test.csproj +++ b/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Tests/Microsoft.Build.NuGetSdkResolver.Test.csproj @@ -1,10 +1,14 @@ - + + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for Microsoft.Build.NuGetSdkResolver. diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.csproj b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.csproj index fcad9c81527..d85aa5977e2 100644 --- a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.csproj @@ -1,10 +1,13 @@ + + true + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Build.Tasks.Console. diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Pack.Test/NuGet.Build.Tasks.Pack.Test.csproj b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Pack.Test/NuGet.Build.Tasks.Pack.Test.csproj index 77ed6f634cb..a28aff0edc3 100644 --- a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Pack.Test/NuGet.Build.Tasks.Pack.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Pack.Test/NuGet.Build.Tasks.Pack.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Build.Tasks.Pack. @@ -20,7 +24,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/NuGet.Build.Tasks.Test.csproj b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/NuGet.Build.Tasks.Test.csproj index 883e044bdf0..84f837c34e6 100644 --- a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/NuGet.Build.Tasks.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/NuGet.Build.Tasks.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Build.Tasks. diff --git a/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/NuGet.CommandLine.Xplat.Tests.csproj b/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/NuGet.CommandLine.Xplat.Tests.csproj index 25074a356fb..d79e50c6fa6 100644 --- a/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/NuGet.CommandLine.Xplat.Tests.csproj +++ b/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/NuGet.CommandLine.Xplat.Tests.csproj @@ -1,10 +1,14 @@ + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.CommandLine.XPlat. @@ -18,7 +22,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/NuGet.Commands.Test.csproj b/test/NuGet.Core.Tests/NuGet.Commands.Test/NuGet.Commands.Test.csproj index 46daf2bd892..3824242ea32 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/NuGet.Commands.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/NuGet.Commands.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Commands. @@ -15,7 +19,7 @@ - + @@ -32,7 +36,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests.cs index 3b84d31c2b6..3e362fd62db 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/RestoreCommandTests.cs @@ -971,7 +971,7 @@ public async Task RestoreCommand_ImportsNoMatchAsync() } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public async Task RestoreCommand_InvalidSignedPackageAsync() { diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs index 2c7e52f0737..ea91dd9108e 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using NuGet.Common; using NuGet.Test.Utility; +using Test.Utility.Signing; using Xunit; namespace NuGet.Commands.Test @@ -108,7 +109,8 @@ public async Task ExecuteCommandAsync_WithAmbiguousMatch_ThrowsAsync() using (var test = await Test.CreateAsync(_fixture.GetDefaultCertificate())) { test.Args.CertificateSubjectName = "Root"; - test.Args.CertificateStoreLocation = StoreLocation.LocalMachine; + //X509 store is opened in ReadOnly mode in this code path. Hence StoreLocation is set to LocalMachine. + test.Args.CertificateStoreLocation = CertificateStoreUtilities.GetTrustedCertificateStoreLocation(readOnly: true); test.Args.CertificateStoreName = StoreName.Root; var exception = await Assert.ThrowsAsync( @@ -150,7 +152,6 @@ public async Task ExecuteCommandAsync_WithMultiplePackagesAndInvalidCertificate_ } } #endif - private static byte[] GetResource(string name) { return ResourceTestUtility.GetResourceBytes( diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/TrustedSignerActionsProviderTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/TrustedSignerActionsProviderTests.cs index fdc8d40212a..3d0d27a0b37 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/TrustedSignerActionsProviderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/TrustedSignerActionsProviderTests.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using System.Threading; @@ -195,7 +195,7 @@ public async Task SyncTrustedRepositoryAsync_WithExistingRepositoryItem_UpdatesC SettingsTestUtils.DeepEquals(i.Certificates.First(), expectedCert)))); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public async Task AddTrustedSignerAsync_WithNullPackage_ThrowsAsync() { @@ -305,7 +305,7 @@ await actionsProvider.AddTrustedSignerAsync( } [Fact] - public async Task AddTrustedSignersAsync_UnsignedPackage_ThrowsAsync() + public async Task AddTrustedSignerAsync_UnsignedPackage_ThrowsAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -332,7 +332,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_TargetRepository_NonRepositorySignedPackage_ThrowsAsync() + public async Task AddTrustedSignerAsync_TargetRepository_NonRepositorySignedPackage_ThrowsAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -364,7 +364,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_NameAlreadyExists_ThrowsAsync() + public async Task AddTrustedSignerAsync_NameAlreadyExists_ThrowsAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -403,7 +403,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_ServiceIndexAlreadyExists_ThrowsAsync() + public async Task AddTrustedSignerAsync_ServiceIndexAlreadyExists_ThrowsAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -443,7 +443,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_WithUnknownPrimarySignature_ThrowsAsync() + public async Task AddTrustedSignerAsync_WithUnknownPrimarySignature_ThrowsAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -491,7 +491,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_RepositorySignedPackage_AddsRepositoryCorrectlyAsync() + public async Task AddTrustedSignerAsync_RepositorySignedPackage_AddsRepositoryCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -536,7 +536,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_RepositorySignedPackage_WithOwners_AddsRepositoryCorrectlyAsync() + public async Task AddTrustedSignerAsync_RepositorySignedPackage_WithOwners_AddsRepositoryCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -582,7 +582,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_RepositorySignedPackage_WithAllowUntrustedRoot_AddsRepositoryCorrectlyAsync() + public async Task AddTrustedSignerAsync_RepositorySignedPackage_WithAllowUntrustedRoot_AddsRepositoryCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -628,7 +628,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_RepositoryCountersignedPackage_AddsRepositoryCorrectlyAsync() + public async Task AddTrustedSignerAsync_RepositoryCountersignedPackage_AddsRepositoryCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -675,7 +675,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_RepositoryCountersignedPackage_WithOwners_AddsRepositoryCorrectlyAsync() + public async Task AddTrustedSignerAsync_RepositoryCountersignedPackage_WithOwners_AddsRepositoryCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -723,7 +723,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_RepositoryCountersignedPackage_WithAllowUntrustedRoot_AddsRepositoryCorrectlyAsync() + public async Task AddTrustedSignerAsync_RepositoryCountersignedPackage_WithAllowUntrustedRoot_AddsRepositoryCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -771,7 +771,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_AuthorSignedPackage_AddsAuthorCorrectlyAsync() + public async Task AddTrustedSignerAsync_AuthorSignedPackage_AddsAuthorCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); @@ -813,7 +813,7 @@ await actionsProvider.AddTrustedSignerAsync( } [CIOnlyFact] - public async Task AddTrustedSignersAsync_AuthorSignedPackage_WithAllowUntrustedRoot_AddsAuthorCorrectlyAsync() + public async Task AddTrustedSignerAsync_AuthorSignedPackage_WithAllowUntrustedRoot_AddsAuthorCorrectlyAsync() { // Arrange var trustedSignersProvider = new Mock(); diff --git a/test/NuGet.Core.Tests/NuGet.Common.Test/CryptoHashProviderTest.cs b/test/NuGet.Core.Tests/NuGet.Common.Test/CryptoHashProviderTest.cs index 0d6f102b0ca..fc780fcf153 100644 --- a/test/NuGet.Core.Tests/NuGet.Common.Test/CryptoHashProviderTest.cs +++ b/test/NuGet.Core.Tests/NuGet.Common.Test/CryptoHashProviderTest.cs @@ -54,10 +54,14 @@ public void CryptoHashProviderThrowsIfHashAlgorithmIsNotSHA512orSHA256(string ha Assert.NotNull(ex); var tex = Assert.IsAssignableFrom(ex); Assert.Equal("hashAlgorithm", tex.ParamName); - var lines = ex.Message.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - Assert.Equal(2, lines.Length); - Assert.Equal(String.Format("Hash algorithm '{0}' is unsupported. Supported algorithms include: SHA512 and SHA256.", hashAlgorithm), lines[0]); - Assert.True(lines[1].EndsWith("hashAlgorithm")); + var expectedMessage = String.Format("Hash algorithm '{0}' is unsupported. Supported algorithms include: SHA512 and SHA256.", hashAlgorithm); + Assert.Contains(expectedMessage, ex.Message); + //Remove the expected message from the exception message, the rest part should have param info. + //Background of this change: System.ArgumentException(string message, string paramName) used to generate two lines of message before, but changed to generate one line + //in PR: https://github.com/dotnet/coreclr/pull/25185/files#diff-0365d5690376ef849bf908dfc225b8e8 + var paramPart = ex.Message.Substring(ex.Message.IndexOf(expectedMessage) + expectedMessage.Length); + Assert.Contains("Parameter", paramPart); + Assert.Contains("hashAlgorithm", paramPart); } [Theory] diff --git a/test/NuGet.Core.Tests/NuGet.Common.Test/NuGet.Common.Test.csproj b/test/NuGet.Core.Tests/NuGet.Common.Test/NuGet.Common.Test.csproj index 4bd940d3ac6..d68ea671a90 100644 --- a/test/NuGet.Core.Tests/NuGet.Common.Test/NuGet.Common.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Common.Test/NuGet.Common.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Common. @@ -14,7 +18,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.Configuration.Test/NuGet.Configuration.Test.csproj b/test/NuGet.Core.Tests/NuGet.Configuration.Test/NuGet.Configuration.Test.csproj index 713f533ca27..5c31b9e81fa 100644 --- a/test/NuGet.Core.Tests/NuGet.Configuration.Test/NuGet.Configuration.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Configuration.Test/NuGet.Configuration.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Configuration. @@ -14,7 +18,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.DependencyResolver.Core.Tests/NuGet.DependencyResolver.Core.Tests.csproj b/test/NuGet.Core.Tests/NuGet.DependencyResolver.Core.Tests/NuGet.DependencyResolver.Core.Tests.csproj index 1c405fc7734..572bddca237 100644 --- a/test/NuGet.Core.Tests/NuGet.DependencyResolver.Core.Tests/NuGet.DependencyResolver.Core.Tests.csproj +++ b/test/NuGet.Core.Tests/NuGet.DependencyResolver.Core.Tests/NuGet.DependencyResolver.Core.Tests.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.DependencyResolver.Core. diff --git a/test/NuGet.Core.Tests/NuGet.Frameworks.Test/NuGet.Frameworks.Test.csproj b/test/NuGet.Core.Tests/NuGet.Frameworks.Test/NuGet.Frameworks.Test.csproj index e6865f78f09..c413deb77c6 100644 --- a/test/NuGet.Core.Tests/NuGet.Frameworks.Test/NuGet.Frameworks.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Frameworks.Test/NuGet.Frameworks.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Frameworks. @@ -14,7 +18,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.LibraryModel.Tests/NuGet.LibraryModel.Tests.csproj b/test/NuGet.Core.Tests/NuGet.LibraryModel.Tests/NuGet.LibraryModel.Tests.csproj index 964dd2a5895..5c8bb7bdc79 100644 --- a/test/NuGet.Core.Tests/NuGet.LibraryModel.Tests/NuGet.LibraryModel.Tests.csproj +++ b/test/NuGet.Core.Tests/NuGet.LibraryModel.Tests/NuGet.LibraryModel.Tests.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.LibraryModel. diff --git a/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGet.PackageManagement.Test.csproj b/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGet.PackageManagement.Test.csproj index 828d0f4c461..fe3daa3dbc9 100644 --- a/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGet.PackageManagement.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGet.PackageManagement.Test.csproj @@ -4,7 +4,7 @@ $(NETFXTargetFramework) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.PackageManagement. diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/NuGet.Packaging.Test.csproj b/test/NuGet.Core.Tests/NuGet.Packaging.Test/NuGet.Packaging.Test.csproj index 548757bf916..20c8d1bcd69 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/NuGet.Packaging.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/NuGet.Packaging.Test.csproj @@ -1,10 +1,14 @@ + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Packaging. @@ -15,7 +19,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs index 35f69c143fa..f379f70d151 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs @@ -1597,7 +1597,7 @@ await Assert.ThrowsAsync( } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public async Task ValidateIntegrityAsync_WhenSignatureContentNull_Throws() { @@ -1835,7 +1835,7 @@ public void GetContentHash_UnsignedPackage_WhenGivingAFallbackFunctionThatReturn } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [CIOnlyFact] public async Task GetContentHash_IsSameForUnsignedAndSignedPackageAsync() { @@ -1956,18 +1956,11 @@ public void CanVerifySignedPackages_ReturnsValueBasedOnOperatingSystemAndFramewo // Act var result = packageArchiveReader.CanVerifySignedPackages(null); // Assert -#if IS_DESKTOP - // Verify package signature when running in full frameworks - if (RuntimeEnvironmentHelper.IsWindows && !RuntimeEnvironmentHelper.IsMono) - { - Assert.True(result); - } - else - { - Assert.False(result); - } +#if IS_SIGNING_SUPPORTED + // Verify package signature when signing is supported + Assert.True(result); #else - // Cannot verify package signature in not-full frameworks + // Cannot verify package signature when signing is not supported Assert.False(result); #endif } diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageExtractorTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageExtractorTests.cs index b4ed8d47cb0..616bbaa5e9e 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageExtractorTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageExtractorTests.cs @@ -2362,7 +2362,7 @@ public async Task ExtractPackageAsync_RequireMode_UnsignedPackage_PluginPackageR } #endif -#if IS_CORECLR +#if IS_CORECLR && !IS_SIGNING_SUPPORTED [Fact] public async Task ExtractPackageAsync_RequireMode_UnsignedPackage_InCoreCLR_SkipsSigningVerificationAsync() { diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/AttributeUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/AttributeUtilityTests.cs index 382231920b7..c4eb8b83871 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/AttributeUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/AttributeUtilityTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Linq; using System.Security.Cryptography; diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/CertificateChainUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/CertificateChainUtilityTests.cs index 9813fc797fd..29f4c1aaad2 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/CertificateChainUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/CertificateChainUtilityTests.cs @@ -73,7 +73,7 @@ public void GetCertificateChain_WhenCertificateTypeUndefined_Throws() Assert.Equal("certificateType", exception.ParamName); } - [PlatformFact(Platform.Windows, Platform.Linux)] // https://github.com/NuGet/Home/issues/8047 + [Fact] public void GetCertificateChain_WithUntrustedRoot_Throws() { using (var chainHolder = new X509ChainHolder()) @@ -100,19 +100,26 @@ public void GetCertificateChain_WithUntrustedRoot_Throws() if (RuntimeEnvironmentHelper.IsWindows || RuntimeEnvironmentHelper.IsLinux) { +#if NETCORE5_0 + Assert.Equal(2, logger.Warnings); +#else Assert.Equal(RuntimeEnvironmentHelper.IsWindows ? 2 : 1, logger.Warnings); - +#endif SigningTestUtility.AssertOfflineRevocation(logger.LogMessages, LogLevel.Warning); +#if NETCORE5_0 + SigningTestUtility.AssertRevocationStatusUnknown(logger.LogMessages, LogLevel.Warning); +#else if (RuntimeEnvironmentHelper.IsWindows) { SigningTestUtility.AssertRevocationStatusUnknown(logger.LogMessages, LogLevel.Warning); } +#endif } } } - [PlatformFact(Platform.Windows, Platform.Linux)] // https://github.com/NuGet/Home/issues/8047 + [Fact] public void GetCertificateChain_WithUntrustedSelfIssuedCertificate_ReturnsChain() { using (var certificate = _fixture.GetDefaultCertificate()) @@ -131,14 +138,19 @@ public void GetCertificateChain_WithUntrustedSelfIssuedCertificate_ReturnsChain( } Assert.Equal(0, logger.Errors); +#if (IS_DESKTOP || NETCORE5_0) + Assert.Equal(1, logger.Warnings); +#else Assert.Equal(RuntimeEnvironmentHelper.IsLinux ? 2 : 1, logger.Warnings); - +#endif SigningTestUtility.AssertUntrustedRoot(logger.LogMessages, LogLevel.Warning); +#if !NETCORE5_0 if (RuntimeEnvironmentHelper.IsLinux) { SigningTestUtility.AssertOfflineRevocation(logger.LogMessages, LogLevel.Warning); } +#endif } } diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdTests.cs index c63c07cb875..25e39bf9cb7 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdTests.cs @@ -36,7 +36,7 @@ public void Read_WithInvalidAsn1_Throws() () => EssCertId.Read(new byte[] { 0x30, 0x0b })); } -#if !IS_CORECLR +#if IS_SIGNING_SUPPORTED [Fact] public void Read_WithValidInput_ReturnsEssCertId() { diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdV2Tests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdV2Tests.cs index 7969df8bfd9..9d005a41aac 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdV2Tests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/EssCertIdV2Tests.cs @@ -168,7 +168,7 @@ public void Read_WithNonDefaultAlgorithmIdentifier_ReturnsEssCertIdV2() SigningTestUtility.VerifyByteArrays(bcIssuerSerial.Serial.Value.ToByteArray(), essCertIdV2.IssuerSerial.SerialNumber); } -#if !IS_CORECLR +#if IS_SIGNING_SUPPORTED [Fact] public void Read_WithValidInput_ReturnsEssCertId() { diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/PrimarySignatureTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/PrimarySignatureTests.cs index 39199bc84e9..6a16317678a 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/PrimarySignatureTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/PrimarySignatureTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/ReadOnlyBufferedStreamTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/ReadOnlyBufferedStreamTests.cs index e693f00c2d1..020abfd9bdf 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/ReadOnlyBufferedStreamTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/ReadOnlyBufferedStreamTests.cs @@ -249,7 +249,7 @@ public void WriteTimeout_Setter_SetsValueOnUnderlyingStream() } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public void Close_WhenLeaveOpenFalse_DisposesUnderlyingStream() { diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/RepositoryCountersignatureTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/RepositoryCountersignatureTests.cs index 20a18861eb0..8c34ef7f080 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/RepositoryCountersignatureTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/RepositoryCountersignatureTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.Collections.Generic; using System.Linq; diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/Rfc3161TimestampProviderTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/Rfc3161TimestampProviderTests.cs new file mode 100644 index 00000000000..48815d74fcc --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/Rfc3161TimestampProviderTests.cs @@ -0,0 +1,43 @@ +// 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 IS_SIGNING_SUPPORTED +using System.Collections.Generic; +using NuGet.Packaging.Signing; +using Xunit; + +namespace NuGet.Packaging.Test.SigningTests +{ + public class Rfc3161TimestampProviderTests + { + public static IEnumerable NonceData + { + get + { +#if IS_DESKTOP + yield return new object[] { new byte[] { 0xff, 0x00 }, new byte[] { 0xff, 0x01 } }; + yield return new object[] { new byte[] { 0xff, 0x01 }, new byte[] { 0xff, 0x01 } }; + yield return new object[] { new byte[] { 0xff, 0x7f }, new byte[] { 0xff, 0x7f } }; + yield return new object[] { new byte[] { 0xff, 0x80 }, new byte[] { 0xff, 0x01 } }; + yield return new object[] { new byte[] { 0xff, 0xff }, new byte[] { 0xff, 0x7f } }; +#else + yield return new object[] { new byte[] { 0x00, 0xff }, new byte[] { 0x00, 0xff } }; + yield return new object[] { new byte[] { 0x01, 0xff }, new byte[] { 0x01, 0xff } }; + yield return new object[] { new byte[] { 0x7f, 0xff }, new byte[] { 0x7f, 0xff } }; + yield return new object[] { new byte[] { 0x80, 0xff }, new byte[] { 0x00, 0xff } }; + yield return new object[] { new byte[] { 0xff, 0xff }, new byte[] { 0x7f, 0xff } }; +#endif + } + } + + [Theory] + [MemberData(nameof(NonceData))] + public void EnsureValidNonce_Always_EnsuresValidNonce(byte[] actualNonce, byte[] expectedNonce) + { + Rfc3161TimestampProvider.EnsureValidNonce(actualNonce); + + Assert.Equal(expectedNonce, actualNonce); + } + } +} +#endif diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs index 5e6fd38a398..ad86d149397 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureTrustAndValidityVerificationProviderTests.cs @@ -14,7 +14,7 @@ namespace NuGet.Packaging.Test { public class SignatureTrustAndValidityVerificationProviderTests { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private static readonly Lazy _signature = new Lazy( () => PrimarySignature.Load(SigningTestUtility.GetResourceBytes(".signature.p7s"))); #endif @@ -25,7 +25,7 @@ public SignatureTrustAndValidityVerificationProviderTests() _provider = new SignatureTrustAndValidityVerificationProvider(); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public async Task GetTrustResultAsync_WhenPackageIsNull_Throws() { @@ -53,7 +53,7 @@ public async Task GetTrustResultAsync_WhenSignatureIsNull_Throws() Assert.Equal("signature", exception.ParamName); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public async Task GetTrustResultAsync_WhenSettingsIsNull_Throws() { diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureUtilityTests.cs index 1607159a045..3a0c06797e6 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignatureUtilityTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.IO; using System.Threading; diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveIOUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveIOUtilityTests.cs index c911cd72d24..8f9e003d53b 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveIOUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveIOUtilityTests.cs @@ -165,7 +165,7 @@ public void ReadAndHashUntilPosition_WhenPositionBeforeCurrentReadPosition_Throw } } -#if !IS_CORECLR +#if IS_SIGNING_SUPPORTED [Fact] public void ReadAndHashUntilPosition_WhenPositionAtStart_ReadsAndHashes() { @@ -248,7 +248,7 @@ public void HashBytes_WhenBytesNullOrEmpty_Throws(byte[] bytes) } } -#if !IS_CORECLR +#if IS_SIGNING_SUPPORTED [Fact] public void HashBytes_WithInputBytes_Hashes() { @@ -486,7 +486,7 @@ protected override void Dispose(bool disposing) internal string GetHash() { -#if !IS_CORECLR +#if IS_SIGNING_SUPPORTED HashAlgorithm.TransformFinalBlock(new byte[0], inputOffset: 0, inputCount: 0); return Convert.ToBase64String(HashAlgorithm.Hash); diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveTests.cs index f8fa6c9aaac..40969f77eaf 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.IO; using System.Threading; using System.Threading.Tasks; diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveUtilityTests.cs index ff6ab82aedb..a3644f6353f 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SignedPackageArchiveUtilityTests.cs @@ -257,7 +257,7 @@ public void GetPackageContentHash_WithCompressedSignatureFileEntry_NotThrows() } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public async Task RemoveRepositorySignaturesAsync_WithNullInput_Throws() { @@ -542,7 +542,7 @@ public void Dispose() } } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private sealed class RemoveTest : IDisposable { private bool _isDisposed; diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningOptionsTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningOptionsTests.cs index a032b558bba..4902b2eb6f0 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningOptionsTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningOptionsTests.cs @@ -1,7 +1,7 @@ // 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 IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System; using System.IO; using Moq; diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningUtilityTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningUtilityTests.cs index 55bbd965d5b..b6e88fbc48b 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningUtilityTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/SigningTests/SigningUtilityTests.cs @@ -6,7 +6,7 @@ using System.IO; using System.IO.Compression; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using System.Security.Cryptography.X509Certificates; @@ -94,7 +94,7 @@ public void Verify_WithNotYetValidCertificate_Throws() } } - [PlatformFact(Platform.Windows, Platform.Linux)] // https://github.com/NuGet/Home/issues/8047 + [Fact] public void Verify_WhenChainBuildingFails_Throws() { using (var certificate = _fixture.GetExpiredCertificate()) @@ -112,8 +112,12 @@ public void Verify_WhenChainBuildingFails_Throws() if (RuntimeEnvironmentHelper.IsLinux) { +#if NETCORE5_0 + Assert.Equal(1, logger.Warnings); +#else Assert.Equal(2, logger.Warnings); SigningTestUtility.AssertRevocationStatusUnknown(logger.LogMessages, LogLevel.Warning); +#endif } else { @@ -125,7 +129,7 @@ public void Verify_WhenChainBuildingFails_Throws() } } - [PlatformFact(Platform.Windows, Platform.Linux)] // https://github.com/NuGet/Home/issues/8047 + [Fact] public void Verify_WithUntrustedSelfSignedCertificate_Succeeds() { using (var certificate = _fixture.GetDefaultCertificate()) @@ -136,18 +140,26 @@ public void Verify_WithUntrustedSelfSignedCertificate_Succeeds() SigningUtility.Verify(request, logger); Assert.Equal(0, logger.Errors); +#if (IS_DESKTOP || NETCORE5_0) + Assert.Equal(1, logger.Warnings); +#else Assert.Equal(RuntimeEnvironmentHelper.IsLinux ? 2 : 1, logger.Warnings); +#endif SigningTestUtility.AssertUntrustedRoot(logger.LogMessages, LogLevel.Warning); + +#if !NETCORE5_0 if (RuntimeEnvironmentHelper.IsLinux) { SigningTestUtility.AssertOfflineRevocation(logger.LogMessages, LogLevel.Warning); } +#endif } + } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED [Fact] public void CreateSignedAttributes_SignPackageRequest_WhenRequestNull_Throws() { @@ -527,14 +539,8 @@ public async Task SignAsync_WhenChainBuildingFails_ThrowsAsync() Assert.Equal(1, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); - Assert.Contains(test.Logger.LogMessages, message => - message.Code == NuGetLogCode.NU3018 && - message.Level == LogLevel.Error && - message.Message == "A required certificate is not within its validity period when verifying against the current system clock or the timestamp in the signed file."); - Assert.Contains(test.Logger.LogMessages, message => - message.Code == NuGetLogCode.NU3018 && - message.Level == LogLevel.Warning && - message.Message == "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider."); + SigningTestUtility.AssertNotTimeValid(test.Logger.LogMessages, LogLevel.Error); + SigningTestUtility.AssertUntrustedRoot(test.Logger.LogMessages, LogLevel.Warning); } } @@ -557,7 +563,7 @@ public async Task SignAsync_WithUntrustedSelfSignedCertificate_SucceedsAsync() Assert.Equal(0, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); Assert.Equal(1, test.Logger.Messages.Count()); - Assert.True(test.Logger.Messages.Contains("A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.")); + SigningTestUtility.AssertUntrustedRoot(test.Logger.LogMessages, LogLevel.Warning); } } @@ -601,7 +607,7 @@ public async Task SignAsync_WhenPackageEntryCountWouldRequireZip64_FailsAsync() Assert.Equal(0, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); Assert.Equal(1, test.Logger.Messages.Count()); - Assert.True(test.Logger.Messages.Contains("A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.")); + SigningTestUtility.AssertUntrustedRoot(test.Logger.LogMessages, LogLevel.Warning); } } } diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/NuGet.ProjectModel.Test.csproj b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/NuGet.ProjectModel.Test.csproj index a6fb46d4e68..438e77c0566 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/NuGet.ProjectModel.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/NuGet.ProjectModel.Test.csproj @@ -1,10 +1,14 @@ + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.ProjectModel. diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/DownloadResourceResultTests.cs b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/DownloadResourceResultTests.cs index 33ece96edc4..afcd6664824 100644 --- a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/DownloadResourceResultTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/DownloadResourceResultTests.cs @@ -25,11 +25,16 @@ public void Constructor_Status_ThrowsForInvalidStatus(DownloadResourceResultStat { var exception = Assert.Throws(() => new DownloadResourceResult(status)); - var expectedMessage = $"A stream should be provided when the result is available.{Environment.NewLine}" - + "Parameter name: status"; - + var expectedMessage = "A stream should be provided when the result is available."; + Assert.Equal("status", exception.ParamName); - Assert.Equal(expectedMessage, exception.Message); + Assert.Contains(expectedMessage, exception.Message); + + //Remove the expected message from the exception message, the rest part should have param info. + //Background of this change: System.ArgumentException(string message, string paramName) used to generate two lines of message before, but changed to generate one line + //in PR: https://github.com/dotnet/coreclr/pull/25185/files#diff-0365d5690376ef849bf908dfc225b8e8 + var paramPart = exception.Message.Substring(exception.Message.IndexOf(expectedMessage) + expectedMessage.Length); + Assert.Contains("status", paramPart); } [Theory] diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/NuGet.Protocol.Tests.csproj b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/NuGet.Protocol.Tests.csproj index f834bef5a76..55779753104 100644 --- a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/NuGet.Protocol.Tests.csproj +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/NuGet.Protocol.Tests.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Protocol. @@ -25,7 +29,7 @@ - + diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Plugins/WindowsEmbeddedSignatureVerifierTests.cs b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Plugins/WindowsEmbeddedSignatureVerifierTests.cs index d8d68d30f84..f7eb743ad4e 100644 --- a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Plugins/WindowsEmbeddedSignatureVerifierTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Plugins/WindowsEmbeddedSignatureVerifierTests.cs @@ -22,10 +22,17 @@ public WindowsEmbeddedSignatureVerifierTests() [InlineData("")] public void IsValid_ThrowsForNullOrEmpty(string filePath) { - var expectedMessage = $"Argument cannot be null or empty.{Environment.NewLine}Parameter name: filePath"; + var expectedMessage = "Argument cannot be null or empty."; + var expectedParam = "filePath"; var exception = Assert.Throws(() => _verifier.IsValid(filePath)); - Assert.Equal(expectedMessage, exception.Message); + Assert.Contains(expectedMessage, exception.Message); + Assert.Equal(expectedParam, exception.ParamName); + //Remove the expected message from the exception message, the rest part should have param info. + //Background of this change: System.ArgumentException(string message, string paramName) used to generate two lines of message before, but changed to generate one line + //in PR: https://github.com/dotnet/coreclr/pull/25185/files#diff-0365d5690376ef849bf908dfc225b8e8 + var paramPart = exception.Message.Substring(exception.Message.IndexOf(expectedMessage) + expectedMessage.Length); + Assert.Contains(expectedParam, paramPart); } [PlatformFact(Platform.Windows)] diff --git a/test/NuGet.Core.Tests/NuGet.Resolver.Test/NuGet.Resolver.Test.csproj b/test/NuGet.Core.Tests/NuGet.Resolver.Test/NuGet.Resolver.Test.csproj index 19faf2c11ed..657af7a5aca 100644 --- a/test/NuGet.Core.Tests/NuGet.Resolver.Test/NuGet.Resolver.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Resolver.Test/NuGet.Resolver.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Resolver. diff --git a/test/NuGet.Core.Tests/NuGet.Shared.Tests/NuGet.Shared.Tests.csproj b/test/NuGet.Core.Tests/NuGet.Shared.Tests/NuGet.Shared.Tests.csproj index 6c68d67269a..8027ab1948a 100644 --- a/test/NuGet.Core.Tests/NuGet.Shared.Tests/NuGet.Shared.Tests.csproj +++ b/test/NuGet.Core.Tests/NuGet.Shared.Tests/NuGet.Shared.Tests.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for the utilities included using shared compilation. diff --git a/test/NuGet.Core.Tests/NuGet.Versioning.Test/ExceptionAssert.cs b/test/NuGet.Core.Tests/NuGet.Versioning.Test/ExceptionAssert.cs index 1a36c13e902..69f55a060f4 100644 --- a/test/NuGet.Core.Tests/NuGet.Versioning.Test/ExceptionAssert.cs +++ b/test/NuGet.Core.Tests/NuGet.Versioning.Test/ExceptionAssert.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -75,13 +75,16 @@ public static void ThrowsArgumentException(Action act, string paramName, string public static void ThrowsArgumentException(Action act, string paramName, string message) where TArgException : ArgumentException { Throws(act, ex => - { - Assert.Equal(paramName, ex.ParamName); - var lines = ex.Message.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - Assert.Equal(2, lines.Length); - Assert.Equal(message, lines[0]); - Assert.True(lines[1].EndsWith(paramName)); - }); + { + Assert.Equal(paramName, ex.ParamName); + Assert.Contains(message, ex.Message); + //Remove the expected message from the exception message, the rest part should have param info. + //Background of this change: System.ArgumentException(string message, string paramName) used to generate two lines of message before, but changed to generate one line + //in PR: https://github.com/dotnet/coreclr/pull/25185/files#diff-0365d5690376ef849bf908dfc225b8e8 + var paramPart = ex.Message.Substring(ex.Message.IndexOf(message) + message.Length); + Assert.Contains("Parameter", paramPart); + Assert.Contains(paramName, paramPart); + }); } } } diff --git a/test/NuGet.Core.Tests/NuGet.Versioning.Test/NuGet.Versioning.Test.csproj b/test/NuGet.Core.Tests/NuGet.Versioning.Test/NuGet.Versioning.Test.csproj index f831dae9b1a..05224e60d88 100644 --- a/test/NuGet.Core.Tests/NuGet.Versioning.Test/NuGet.Versioning.Test.csproj +++ b/test/NuGet.Core.Tests/NuGet.Versioning.Test/NuGet.Versioning.Test.csproj @@ -1,10 +1,14 @@  + + true + + $(TargetFrameworksExe) - $(NETCoreTargetFramework) + $(NETCoreTargetFrameworks) true true Unit tests for NuGet.Versioning. diff --git a/test/TestExtensions/TestablePlugin/TestablePlugin.csproj b/test/TestExtensions/TestablePlugin/TestablePlugin.csproj index e0da25d37b0..1569a572872 100644 --- a/test/TestExtensions/TestablePlugin/TestablePlugin.csproj +++ b/test/TestExtensions/TestablePlugin/TestablePlugin.csproj @@ -1,4 +1,8 @@  + + true + + diff --git a/test/TestUtilities/Test.Utility/Signing/CertificateAuthority.cs b/test/TestUtilities/Test.Utility/Signing/CertificateAuthority.cs index 3a3ee685c1c..ba9a917d312 100644 --- a/test/TestUtilities/Test.Utility/Signing/CertificateAuthority.cs +++ b/test/TestUtilities/Test.Utility/Signing/CertificateAuthority.cs @@ -152,7 +152,7 @@ public void Revoke(X509Certificate certificate, RevocationReason reason, DateTim new RevocationInfo(certificate.SerialNumber, revocationDate, reason)); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public override void Respond(HttpListenerContext context) { if (context == null) @@ -332,4 +332,4 @@ internal RevocationInfo(BigInteger serialNumber, DateTimeOffset revocationDate, } } } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/Signing/CertificateStoreUtilities.cs b/test/TestUtilities/Test.Utility/Signing/CertificateStoreUtilities.cs new file mode 100644 index 00000000000..07887bfff5d --- /dev/null +++ b/test/TestUtilities/Test.Utility/Signing/CertificateStoreUtilities.cs @@ -0,0 +1,22 @@ +// 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; +using NuGet.Common; + +namespace Test.Utility.Signing +{ + public static class CertificateStoreUtilities + { + public static StoreLocation GetTrustedCertificateStoreLocation(bool readOnly = false) + { + // According to https://github.com/dotnet/runtime/blob/master/docs/design/features/cross-platform-cryptography.md#x509store + // use different approaches for Windows, Mac and Linux. + if(readOnly) + { + return StoreLocation.LocalMachine; + } + return (RuntimeEnvironmentHelper.IsWindows || RuntimeEnvironmentHelper.IsMacOSX) ? StoreLocation.LocalMachine : StoreLocation.CurrentUser; + } + } +} diff --git a/test/TestUtilities/Test.Utility/Signing/CertificateUtilities.cs b/test/TestUtilities/Test.Utility/Signing/CertificateUtilities.cs index c7441a3fe92..eec3c134151 100644 --- a/test/TestUtilities/Test.Utility/Signing/CertificateUtilities.cs +++ b/test/TestUtilities/Test.Utility/Signing/CertificateUtilities.cs @@ -2,15 +2,19 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; using NuGet.Common; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; -using Org.BouncyCastle.X509; +using Xunit; +using X509Certificate = Org.BouncyCastle.X509.X509Certificate; namespace Test.Utility.Signing { - internal static class CertificateUtilities + public static class CertificateUtilities { internal static AsymmetricCipherKeyPair CreateKeyPair(int strength = 2048) { @@ -35,5 +39,33 @@ internal static string GenerateRandomId() { return Guid.NewGuid().ToString(); } + + public static X509Certificate2 GetCertificateWithPrivateKey(X509Certificate bcCertificate, AsymmetricCipherKeyPair keyPair) + { + Assert.IsType(keyPair.Private); + + var privateKeyParameters = (RsaPrivateCrtKeyParameters)keyPair.Private; +#if IS_DESKTOP + RSA privateKey = DotNetUtilities.ToRSA(privateKeyParameters); + + var certificate = new X509Certificate2(bcCertificate.GetEncoded()); + + certificate.PrivateKey = privateKey; +#else + RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(privateKeyParameters); + + var privateKey = new RSACryptoServiceProvider(); + + privateKey.ImportParameters(rsaParameters); + + X509Certificate2 certificate; + + using (var certificateTmp = new X509Certificate2(bcCertificate.GetEncoded())) + { + certificate = RSACertificateExtensions.CopyWithPrivateKey(certificateTmp, privateKey); + } +#endif + return certificate; + } } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/Signing/HttpResponder.cs b/test/TestUtilities/Test.Utility/Signing/HttpResponder.cs index 45f7a357086..92719ad214d 100644 --- a/test/TestUtilities/Test.Utility/Signing/HttpResponder.cs +++ b/test/TestUtilities/Test.Utility/Signing/HttpResponder.cs @@ -11,7 +11,7 @@ public abstract class HttpResponder : IHttpResponder { public abstract Uri Url { get; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public abstract void Respond(HttpListenerContext context); protected static bool IsGet(HttpListenerRequest request) @@ -43,4 +43,4 @@ protected static void WriteResponseBody(HttpListenerResponse response, byte[] by } #endif } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/Signing/IHttpResonder.cs b/test/TestUtilities/Test.Utility/Signing/IHttpResonder.cs index 50f9827794b..b834929206c 100644 --- a/test/TestUtilities/Test.Utility/Signing/IHttpResonder.cs +++ b/test/TestUtilities/Test.Utility/Signing/IHttpResonder.cs @@ -10,8 +10,8 @@ public interface IHttpResponder { Uri Url { get; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED void Respond(HttpListenerContext context); #endif } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/Signing/ISigningTestServer.cs b/test/TestUtilities/Test.Utility/Signing/ISigningTestServer.cs index ed17fd07b47..98b5800f4b7 100644 --- a/test/TestUtilities/Test.Utility/Signing/ISigningTestServer.cs +++ b/test/TestUtilities/Test.Utility/Signing/ISigningTestServer.cs @@ -9,8 +9,8 @@ public interface ISigningTestServer { Uri Url { get; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED IDisposable RegisterResponder(IHttpResponder responder); #endif } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/Signing/OcspResponder.cs b/test/TestUtilities/Test.Utility/Signing/OcspResponder.cs index 7f562e864c2..016a256e04c 100644 --- a/test/TestUtilities/Test.Utility/Signing/OcspResponder.cs +++ b/test/TestUtilities/Test.Utility/Signing/OcspResponder.cs @@ -49,7 +49,7 @@ public static OcspResponder Create( return new OcspResponder(certificateAuthority, options); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public override void Respond(HttpListenerContext context) { if (context == null) @@ -174,4 +174,4 @@ private X509Certificate[] GetCertificateChain() return certificates.ToArray(); } } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/Signing/SignatureTestUtility.cs b/test/TestUtilities/Test.Utility/Signing/SignatureTestUtility.cs index 7d674c7b05b..cd99bdbfe03 100644 --- a/test/TestUtilities/Test.Utility/Signing/SignatureTestUtility.cs +++ b/test/TestUtilities/Test.Utility/Signing/SignatureTestUtility.cs @@ -15,7 +15,7 @@ namespace Test.Utility.Signing { public static class SignatureTestUtility { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED // Central Directory file header size excluding signature, file name, extra field and file comment private const uint CentralDirectoryFileHeaderSizeWithoutSignature = 46; diff --git a/test/TestUtilities/Test.Utility/Signing/SignedArchiveTestUtility.cs b/test/TestUtilities/Test.Utility/Signing/SignedArchiveTestUtility.cs index d763b71e35d..3e12bd30f36 100644 --- a/test/TestUtilities/Test.Utility/Signing/SignedArchiveTestUtility.cs +++ b/test/TestUtilities/Test.Utility/Signing/SignedArchiveTestUtility.cs @@ -6,7 +6,7 @@ using System.IO; using System.IO.Compression; using System.Linq; -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED using System.Security.Cryptography.Pkcs; #endif using System.Security.Cryptography.X509Certificates; @@ -22,7 +22,7 @@ namespace Test.Utility.Signing { public static class SignedArchiveTestUtility { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Generates an author signed copy of a package and returns the path to that package /// This method can timestamp a package and should only be used with tests marked with [CIOnlyFact] @@ -53,7 +53,8 @@ public static async Task AuthorSignPackageAsync( return await AuthorSignPackageAsync(certificate, timestampService, signatureHashAlgorithm, timestampHashAlgorithm, signedPackagePath, tempPath); } - +#endif +#if IS_SIGNING_SUPPORTED /// /// Generates an author signed copy of a package and returns the path to that package /// This method can timestamp a package and should only be used with tests marked with [CIOnlyFact] @@ -89,7 +90,8 @@ public static async Task AuthorSignPackageAsync( return await AuthorSignPackageAsync(certificate, timestampService, signatureHashAlgorithm, timestampHashAlgorithm, signedPackagePath, tempPath); } - +#endif +#if IS_SIGNING_SUPPORTED private static async Task AuthorSignPackageAsync( X509Certificate2 certificate, Uri timestampService, @@ -286,7 +288,7 @@ public static async Task RepositoryCountersignPrimarySignature return await signatureProvider.CreateRepositoryCountersignatureAsync(request, signature, testLogger, CancellationToken.None); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED // This generates a package with a basic signed CMS. // The signature MUST NOT have any signed or unsigned attributes. public static async Task SignPackageFileWithBasicSignedCmsAsync( @@ -371,7 +373,7 @@ public static async Task IsRepositoryCountersignedAsync(Stream package) var primarySignature = await reader.GetPrimarySignatureAsync(CancellationToken.None); if (primarySignature != null) { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED return SignatureUtility.HasRepositoryCountersignature(primarySignature); #endif } diff --git a/test/TestUtilities/Test.Utility/Signing/SigningTestServer.cs b/test/TestUtilities/Test.Utility/Signing/SigningTestServer.cs index 6edfbb9fd93..526249e1d29 100644 --- a/test/TestUtilities/Test.Utility/Signing/SigningTestServer.cs +++ b/test/TestUtilities/Test.Utility/Signing/SigningTestServer.cs @@ -14,14 +14,14 @@ namespace Test.Utility.Signing public sealed class SigningTestServer : ISigningTestServer, IDisposable { private readonly ConcurrentDictionary _responders = new ConcurrentDictionary(); -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private readonly HttpListener _listener; private bool _isDisposed; #endif public Uri Url { get; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private SigningTestServer(HttpListener listener, Uri url) { _listener = listener; @@ -31,7 +31,7 @@ private SigningTestServer(HttpListener listener, Uri url) public void Dispose() { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED if (!_isDisposed) { _listener.Stop(); @@ -56,7 +56,7 @@ public IDisposable RegisterResponder(IHttpResponder responder) public static Task CreateAsync() { -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED var portReserver = new PortReserver(); return portReserver.ExecuteAsync( @@ -87,14 +87,16 @@ public static Task CreateAsync() #endif } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED private static string GetBaseAbsolutePath(Uri url) { var path = url.PathAndQuery; return path.Substring(0, path.IndexOf('/', 1) + 1); } +#endif +#if IS_SIGNING_SUPPORTED private void HandleRequest(ManualResetEventSlim mutex, CancellationToken cancellationToken) { mutex.Set(); @@ -168,4 +170,4 @@ public void Dispose() } } } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/Signing/SigningTestUtility.cs b/test/TestUtilities/Test.Utility/Signing/SigningTestUtility.cs index e1af25638ec..df49a9d4cde 100644 --- a/test/TestUtilities/Test.Utility/Signing/SigningTestUtility.cs +++ b/test/TestUtilities/Test.Utility/Signing/SigningTestUtility.cs @@ -147,7 +147,7 @@ public static IList> GenerateCertificateChain(i IsCA = true }; - cert = TestCertificate.Generate(actionGenerator, chainCertificateRequest).WithPrivateKeyAndTrust(StoreName.Root, StoreLocation.LocalMachine); + cert = TestCertificate.Generate(actionGenerator, chainCertificateRequest).WithPrivateKeyAndTrust(StoreName.Root); issuer = cert; } else if (i < length - 1) // intermediate CA cert @@ -161,7 +161,7 @@ public static IList> GenerateCertificateChain(i Issuer = issuer.Source.Cert }; - cert = TestCertificate.Generate(actionGenerator, chainCertificateRequest).WithPrivateKeyAndTrust(StoreName.CertificateAuthority, StoreLocation.LocalMachine); + cert = TestCertificate.Generate(actionGenerator, chainCertificateRequest).WithPrivateKeyAndTrust(StoreName.CertificateAuthority); issuer = cert; } else // leaf cert @@ -175,7 +175,7 @@ public static IList> GenerateCertificateChain(i Issuer = issuer.Source.Cert }; - cert = TestCertificate.Generate(actionGenerator, chainCertificateRequest).WithPrivateKeyAndTrust(StoreName.My, StoreLocation.LocalMachine); + cert = TestCertificate.Generate(actionGenerator, chainCertificateRequest).WithPrivateKeyAndTrust(StoreName.My); } certChain.Add(cert); @@ -243,7 +243,12 @@ private static X509Certificate2 GenerateCertificate( var keyUsage = X509KeyUsageFlags.DigitalSignature; - if (chainCertificateRequest != null) + if (chainCertificateRequest == null) + { + // Self-signed certificates should have this flag set. + keyUsage |= X509KeyUsageFlags.KeyCertSign; + } + else { if (chainCertificateRequest.Issuer != null) { @@ -286,6 +291,7 @@ private static X509Certificate2 GenerateCertificate( var padding = paddingMode.ToPadding(); var request = new CertificateRequest(subjectDN, rsa, hashAlgorithm.ConvertToSystemSecurityHashAlgorithmName(), padding); + bool isCa = isSelfSigned ? true : (chainCertificateRequest?.IsCA ?? false); certGen.NotAfter = notAfter ?? DateTime.UtcNow.Add(TimeSpan.FromMinutes(30)); certGen.NotBefore = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(30)); @@ -301,7 +307,7 @@ private static X509Certificate2 GenerateCertificate( certGen.Extensions.Add( new X509KeyUsageExtension(keyUsage, critical: false)); certGen.Extensions.Add( - new X509BasicConstraintsExtension(certificateAuthority: chainCertificateRequest?.IsCA ?? false, hasPathLengthConstraint: false, pathLengthConstraint: 0, critical: true)); + new X509BasicConstraintsExtension(certificateAuthority: isCa, hasPathLengthConstraint: false, pathLengthConstraint: 0, critical: true)); // Allow changes modifyGenerator?.Invoke(certGen); @@ -490,7 +496,7 @@ public static SignedCms GenerateSignedCms(X509Certificate2 cert, byte[] content) return cms; } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED /// /// Generates a SignedCMS object for some content. /// @@ -541,7 +547,7 @@ public static TrustedTestCert GenerateTrustedTestCertificate() // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - return TestCertificate.Generate(actionGenerator).WithTrust(StoreName.Root, StoreLocation.LocalMachine); + return TestCertificate.Generate(actionGenerator).WithTrust(); } public static TrustedTestCert GenerateTrustedTestCertificateExpired() @@ -551,7 +557,7 @@ public static TrustedTestCert GenerateTrustedTestCertificateExp // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - return TestCertificate.Generate(actionGenerator).WithTrust(StoreName.Root, StoreLocation.LocalMachine); + return TestCertificate.Generate(actionGenerator).WithTrust(); } public static TrustedTestCert GenerateTrustedTestCertificateNotYetValid() @@ -561,7 +567,7 @@ public static TrustedTestCert GenerateTrustedTestCertificateNot // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - return TestCertificate.Generate(actionGenerator).WithTrust(StoreName.Root, StoreLocation.LocalMachine); + return TestCertificate.Generate(actionGenerator).WithTrust(); } public static TrustedTestCert GenerateTrustedTestCertificateThatWillExpireSoon(TimeSpan expiresIn) @@ -571,7 +577,7 @@ public static TrustedTestCert GenerateTrustedTestCertificateTha // Code Sign EKU needs trust to a root authority // Add the cert to Root CA list in LocalMachine as it does not prompt a dialog // This makes all the associated tests to require admin privilege - return TestCertificate.Generate(actionGenerator).WithTrust(StoreName.Root, StoreLocation.LocalMachine); + return TestCertificate.Generate(actionGenerator).WithTrust(); } public static bool AreVerifierSettingsEqual(SignedPackageVerifierSettings first, SignedPackageVerifierSettings second) @@ -654,6 +660,8 @@ public static void VerifyByteArrays(byte[] expected, byte[] actual) Assert.Equal(expectedHex, actualHex); } + //We will not change the original X509ChainStatus.StatusInformation of OfflineRevocation if we directly call API CertificateChainUtility.GetCertificateChain (or SigningUtility.Verify) + //So if we use APIs above to verify the results of chain.build, we should use AssertOfflineRevocation public static void AssertOfflineRevocation(IEnumerable issues, LogLevel logLevel) { string offlineRevocation; @@ -677,7 +685,30 @@ public static void AssertOfflineRevocation(IEnumerable issues, LogL issue.Message.Contains(offlineRevocation)); } + //We will change the original X509ChainStatus.StatusInformation of OfflineRevocation to VerifyCertTrustOfflineWhileRevocationModeOffline or VerifyCertTrustOfflineWhileRevocationModeOnline in Signature.cs and Timestamp.cs + //So if we use APIs above to verify the results of chain.build, we should use assert AssertOfflineRevocationOnlineMode and AssertOfflineRevocationOfflineMode + public static void AssertOfflineRevocationOnlineMode(IEnumerable issues, LogLevel logLevel) + { + Assert.Contains(issues, issue => + issue.Code == NuGetLogCode.NU3018 && + issue.Level == logLevel && + issue.Message.Contains("The revocation function was unable to check revocation because the revocation server could not be reached. For more information, visit https://aka.ms/certificateRevocationMode.")); + } + + public static void AssertOfflineRevocationOfflineMode(IEnumerable issues) + { + Assert.Contains(issues, issue => + issue.Code == NuGetLogCode.Undefined && + issue.Level == LogLevel.Information && + issue.Message.Contains("The revocation function was unable to check revocation because the certificate is not available in the cached certificate revocation list and NUGET_CERT_REVOCATION_MODE environment variable has been set to offline. For more information, visit https://aka.ms/certificateRevocationMode.")); + } + public static void AssertRevocationStatusUnknown(IEnumerable issues, LogLevel logLevel) + { + AssertRevocationStatusUnknown(issues, logLevel, NuGetLogCode.NU3018); + } + + public static void AssertRevocationStatusUnknown(IEnumerable issues, LogLevel logLevel, NuGetLogCode code) { string revocationStatusUnknown; @@ -693,9 +724,9 @@ public static void AssertRevocationStatusUnknown(IEnumerable issues { revocationStatusUnknown = "unable to get certificate CRL"; } - + Assert.Contains(issues, issue => - issue.Code == NuGetLogCode.NU3018 && + issue.Code == code && issue.Level == logLevel && issue.Message.Contains(revocationStatusUnknown)); } @@ -710,7 +741,7 @@ public static void AssertUntrustedRoot(IEnumerable issues, LogLevel } else if (RuntimeEnvironmentHelper.IsMacOSX) { - untrustedRoot = "The trust policy was not trusted."; + untrustedRoot = "The certificate was not trusted."; } else { @@ -739,7 +770,7 @@ public static void AssertNotTimeValid(IEnumerable issues, LogLevel { notTimeValid = "certificate has expired"; } - + Assert.Contains(issues, issue => issue.Code == NuGetLogCode.NU3018 && issue.Level == logLevel && diff --git a/test/TestUtilities/Test.Utility/Signing/TestCertificate.cs b/test/TestUtilities/Test.Utility/Signing/TestCertificate.cs index 37830910c44..e69dbf1bc73 100644 --- a/test/TestUtilities/Test.Utility/Signing/TestCertificate.cs +++ b/test/TestUtilities/Test.Utility/Signing/TestCertificate.cs @@ -3,6 +3,7 @@ using System; using System.Security.Cryptography.X509Certificates; +using NuGet.Common; namespace Test.Utility.Signing { @@ -36,17 +37,23 @@ public class TestCertificate /// Trust the PublicCert cert for the life of the object. /// /// Dispose of the object returned! - public TrustedTestCert WithTrust(StoreName storeName = StoreName.TrustedPeople, StoreLocation storeLocation = StoreLocation.CurrentUser) + /// According to https://github.com/dotnet/corefx/blob/master/Documentation/architecture/cross-platform-cryptography.md#x509store + /// Linux could not read/write LocalMachine\Root , but could only read/write CurrentUser\Root + public TrustedTestCert WithTrust() { - return new TrustedTestCert(this, e => PublicCert, storeName, storeLocation); + StoreLocation storeLocation = CertificateStoreUtilities.GetTrustedCertificateStoreLocation(); + + return new TrustedTestCert(this, e => PublicCert, StoreName.Root, storeLocation); } /// /// Trust the PublicCert cert for the life of the object. /// /// Dispose of the object returned! - public TrustedTestCert WithPrivateKeyAndTrust(StoreName storeName = StoreName.TrustedPeople, StoreLocation storeLocation = StoreLocation.CurrentUser) + public TrustedTestCert WithPrivateKeyAndTrust(StoreName storeName = StoreName.TrustedPeople) { + StoreLocation storeLocation = CertificateStoreUtilities.GetTrustedCertificateStoreLocation(); + return new TrustedTestCert(this, e => PublicCertWithPrivateKey, storeName, storeLocation); } diff --git a/test/TestUtilities/Test.Utility/Signing/TimestampService.cs b/test/TestUtilities/Test.Utility/Signing/TimestampService.cs index a79b7d2e93d..eb211b0486e 100644 --- a/test/TestUtilities/Test.Utility/Signing/TimestampService.cs +++ b/test/TestUtilities/Test.Utility/Signing/TimestampService.cs @@ -136,7 +136,7 @@ void customizeCertificate(X509V3CertificateGenerator generator) return new TimestampService(certificateAuthority, certificate, issueCertificateOptions.KeyPair, uri, serviceOptions); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED public override void Respond(HttpListenerContext context) { if (context == null) diff --git a/test/TestUtilities/Test.Utility/Signing/TrustedTestCert.cs b/test/TestUtilities/Test.Utility/Signing/TrustedTestCert.cs index 8c5133c09cd..cf063f37eec 100644 --- a/test/TestUtilities/Test.Utility/Signing/TrustedTestCert.cs +++ b/test/TestUtilities/Test.Utility/Signing/TrustedTestCert.cs @@ -2,7 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.IO; using System.Security.Cryptography.X509Certificates; +using System.Threading; +using NuGet.Common; +using NuGet.Test.Utility; namespace Test.Utility.Signing { @@ -40,6 +44,8 @@ public class TrustedTestCert : IDisposable private bool _isDisposed; + private const string KeychainForMac = "/Library/Keychains/System.keychain"; + public TrustedTestCert(T source, Func getCert, StoreName storeName = StoreName.TrustedPeople, @@ -54,15 +60,23 @@ public TrustedTestCert(T source, maximumValidityPeriod = TimeSpan.FromHours(2); } -#if IS_DESKTOP +#if IS_SIGNING_SUPPORTED if (TrustedCert.NotAfter - TrustedCert.NotBefore > maximumValidityPeriod.Value) { throw new InvalidOperationException($"The certificate used is valid for more than {maximumValidityPeriod}."); } #endif - StoreName = storeName; - StoreLocation = storeLocation; - AddCertificateToStore(); + if (RuntimeEnvironmentHelper.IsMacOSX) + { + AddCertificateToStoreForMacOSX(); + } + else + { + StoreName = storeName; + StoreLocation = storeLocation; + AddCertificateToStore(); + } + ExportCrl(); } @@ -71,6 +85,88 @@ private void AddCertificateToStore() _store = new X509Store(StoreName, StoreLocation); _store.Open(OpenFlags.ReadWrite); _store.Add(TrustedCert); + + //Add wait for Linux, as https://github.com/dotnet/runtime/issues/32608 + //Windows has a live-synchronized model, and on Linux, there is a filesystem/rescan delay problem. + //For performance reasons, dotnet/runtime only check to see if the store has been modified once a second. + if (RuntimeEnvironmentHelper.IsLinux) + { + Thread.Sleep(1500); + + var MaxTries = 30; + + for (var i = 0; i < MaxTries; i++) + { + using (var chain = new X509Chain()) + { + chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; + + if (chain.Build(TrustedCert)) + { + break; + } + else + { + Thread.Sleep(1000); + } + } + } + } + } + + //According to https://github.com/dotnet/runtime/blob/master/docs/design/features/cross-platform-cryptography.md#x509store, + //on macOS the X509Store class is a projection of system trust decisions (read-only), user trust decisions (read-only), and user key storage (read-write). + //So we have to run command to add certificate to System.keychain to make it trusted. + private void AddCertificateToStoreForMacOSX() + { + var certFile = new FileInfo(Path.Combine("/tmp", $"{TrustedCert.Thumbprint}.cer")); + + File.WriteAllBytes(certFile.FullName, TrustedCert.RawData); + + string addToKeyChainCmd = $"sudo security add-trusted-cert -d -r trustRoot " + + $"-k \"{KeychainForMac}\" " + + $"\"{certFile.FullName}\""; + + RunMacCommand(addToKeyChainCmd); + } + + //According to https://github.com/dotnet/runtime/blob/master/docs/design/features/cross-platform-cryptography.md#x509store, + //on macOS the X509Store class is a projection of system trust decisions (read-only), user trust decisions (read-only), and user key storage (read-write). + //So we have to run command to remove certificate from System.keychain to make it untrusted. + private void RemoveTrustedCert() + { + var certFile = new FileInfo(Path.Combine("/tmp", $"{TrustedCert.Thumbprint}.cer")); + + string removeFromKeyChainCmd = $"sudo security delete-certificate -Z {TrustedCert.Thumbprint} \"{KeychainForMac}\""; + + try + { + RunMacCommand(removeFromKeyChainCmd); + } + finally + { + certFile.Delete(); + } + } + + private static void RunMacCommand(string cmd) + { + string workingDirectory = "/bin"; + string args = "-c \"" + cmd + "\""; + + CommandRunnerResult result = CommandRunner.Run("/bin/bash", + workingDirectory, + args, + waitForExit: true, + timeOutInMilliseconds: 60000); + + if (!result.Success) + { + throw new SystemToolException($"Run security command failed with following log information :\n" + + $"exit code = {result.ExitCode} \n" + + $"exit output = {result.Output} \n" + + $"exit error = {result.Errors} \n"); + } } private void ExportCrl() @@ -97,9 +193,16 @@ public void Dispose() { if (!_isDisposed) { - using (_store) + if (RuntimeEnvironmentHelper.IsMacOSX) + { + RemoveTrustedCert(); + } + else { - _store.Remove(TrustedCert); + using (_store) + { + _store.Remove(TrustedCert); + } } DisposeCrl(); @@ -110,4 +213,4 @@ public void Dispose() } } } -} \ No newline at end of file +} diff --git a/test/TestUtilities/Test.Utility/SystemToolException.cs b/test/TestUtilities/Test.Utility/SystemToolException.cs new file mode 100644 index 00000000000..a4b55ae2282 --- /dev/null +++ b/test/TestUtilities/Test.Utility/SystemToolException.cs @@ -0,0 +1,30 @@ +// 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; +using System.Globalization; + +namespace Test.Utility +{ + internal sealed class SystemToolException : Exception + { + public SystemToolException() + { + } + + public SystemToolException(string message) + : base(message) + { + } + + public SystemToolException(string format, params object[] args) + : base(string.Format(CultureInfo.CurrentCulture, format, args)) + { + } + + public SystemToolException(string message, Exception exception) + : base(message, exception) + { + } + } +} diff --git a/test/TestUtilities/Test.Utility/Test.Utility.csproj b/test/TestUtilities/Test.Utility/Test.Utility.csproj index 86312f8495b..96ed273aa5a 100644 --- a/test/TestUtilities/Test.Utility/Test.Utility.csproj +++ b/test/TestUtilities/Test.Utility/Test.Utility.csproj @@ -1,11 +1,15 @@ + + true + + $(TargetFrameworksExe) $(NoWarn);CS1591 - $(NoWarn);CS1998 + $(NoWarn);CS1998 true true true @@ -64,14 +68,14 @@ - + - +