Skip to content

Commit a5685c0

Browse files
authored
Add option to skip test signing on some assemblies (#10695)
* Add SkipAuthenticodeSubjects so we can not re-sign in some cases * Remove flaky assertion
1 parent 6d8001a commit a5685c0

5 files changed

Lines changed: 70 additions & 6 deletions

File tree

build/FindDuplicateFiles.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO;
77
using System.Linq;
88
using System.Security.Cryptography;
9+
using System.Security.Cryptography.X509Certificates;
910
using Microsoft.Build.Framework;
1011

1112
namespace NuGet.Services.Build
@@ -21,6 +22,8 @@ public class FindDuplicateFiles : Microsoft.Build.Utilities.Task
2122
[Output]
2223
public ITaskItem[] DuplicateFiles { get; set; }
2324

25+
public string SkipAuthenticodeSubjects { get; set; }
26+
2427
public override bool Execute()
2528
{
2629
var infos = GetUniqueTaskItemInfo();
@@ -123,6 +126,57 @@ private Dictionary<string, List<TaskItemInfo>> FindDuplicates(List<TaskItemInfo>
123126
BreakTiesWithLeadingHash(filePathToDuplicates, buffer, fileSizePair);
124127
}
125128

129+
if (!string.IsNullOrWhiteSpace(SkipAuthenticodeSubjects))
130+
{
131+
Log.LogMessage("Skipping files with the following Authenticode subjects: {0}", SkipAuthenticodeSubjects);
132+
133+
var skipSubjects = SkipAuthenticodeSubjects
134+
.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
135+
.Select(s => s.Trim())
136+
.ToHashSet(StringComparer.Ordinal);
137+
138+
foreach (var pair in filePathToDuplicates.ToList())
139+
{
140+
var path = pair.Key;
141+
try
142+
{
143+
var cert = X509Certificate.CreateFromSignedFile(path);
144+
var subject = cert.Subject;
145+
146+
if (skipSubjects.Contains(subject))
147+
{
148+
Log.LogMessage(
149+
"Skipping file '{0}' with Authenticode subject '{1}'.",
150+
path,
151+
subject);
152+
153+
filePathToDuplicates.Remove(path);
154+
}
155+
else
156+
{
157+
Log.LogMessage(
158+
"Not skipping file '{0}' with Authenticode subject '{1}'.",
159+
path,
160+
subject);
161+
}
162+
}
163+
catch (Exception ex)
164+
{
165+
if (ex is CryptographicException)
166+
{
167+
// The file is not signed, proceed as normal.
168+
continue;
169+
}
170+
171+
throw;
172+
}
173+
}
174+
}
175+
else
176+
{
177+
Log.LogMessage("No Authenticode subjects to skip were provided.");
178+
}
179+
126180
return filePathToDuplicates;
127181
}
128182

build/FindDuplicateFiles.targets

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
88
<UniqueFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
99
<DuplicateFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
10+
11+
<!--
12+
MicroBuild test signing fails signing a file that is already signed with the target strong name key.
13+
Because of this, when doing test signing we skip files that are already fully signed.
14+
We use the Authenticode subject to identify files that are signed with the real Microsoft key, since those will also have a complete strong name.
15+
Ideally we would have an option to filter out fully signed files directly, but this is not as simple (requires sn.exe to check).
16+
This is obviously not a full proof check, but it's sufficient for test signing (non-production scenarios).
17+
-->
18+
<SkipAuthenticodeSubjects ParameterType="System.String" />
1019
</ParameterGroup>
1120
<Task>
1221
<Code Type="Class" Language="cs" Source="$(MSBuildThisFileDirectory)FindDuplicateFiles.cs" />

build/sign-binaries.proj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<IntermediateOutputPath>$(RepositoryRootDirectory)artifacts\sign\obj\</IntermediateOutputPath>
88
<OutDir>$(RepositoryRootDirectory)</OutDir>
99
<SignTargetsDependOn>BatchSign</SignTargetsDependOn>
10+
<SkipAuthenticodeSubjects Condition="'$(SkipAuthenticodeSubjects)' == '' and '$(SignType)' == 'test'">CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US</SkipAuthenticodeSubjects>
1011
</PropertyGroup>
1112

1213
<ItemGroup>
@@ -29,7 +30,7 @@
2930
TaskParameter="TargetOutputs"
3031
ItemName="UnfilteredFilesToSign" />
3132
</MSBuild>
32-
<FindDuplicateFiles Files="@(UnfilteredFilesToSign)">
33+
<FindDuplicateFiles Files="@(UnfilteredFilesToSign)" SkipAuthenticodeSubjects="$(SkipAuthenticodeSubjects)">
3334
<Output
3435
TaskParameter="UniqueFiles"
3536
ItemName="FilesToSign" />
@@ -51,4 +52,4 @@
5152

5253
<Import Project="FindDuplicateFiles.targets" />
5354
<Import Project="..\packages\MicroBuild.Core\build\MicroBuild.Core.targets" Condition="Exists('..\packages\MicroBuild.Core\build\MicroBuild.Core.targets')" />
54-
</Project>
55+
</Project>

build/sign.microbuild.targets

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<MicroBuild_NuPkgSigningEnabled>false</MicroBuild_NuPkgSigningEnabled>
99
<BatchSign Condition="'$(BatchSign)' == ''">true</BatchSign>
1010
<RepositoryRootDirectory Condition="'$(RepositoryRootDirectory)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'build.ps1'))\</RepositoryRootDirectory>
11+
<SkipAuthenticodeSubjects Condition="'$(SkipAuthenticodeSubjects)' == '' and '$(SignType)' == 'test'">CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US</SkipAuthenticodeSubjects>
1112

1213
<!--
1314
By default, only run EnumerateFilesToSign if we are not batch signing. This property is explicitly set to true when
@@ -145,7 +146,7 @@
145146
<Target
146147
Name="DedupeFilesToSign"
147148
DependsOnTargets="EnumerateFilesToSign">
148-
<FindDuplicateFiles Files="@(UnfilteredFilesToSign)">
149+
<FindDuplicateFiles Files="@(UnfilteredFilesToSign)" SkipAuthenticodeSubjects="$(SkipAuthenticodeSubjects)">
149150
<Output
150151
TaskParameter="UniqueFiles"
151152
ItemName="FilesToSign" />
@@ -155,7 +156,7 @@
155156
</FindDuplicateFiles>
156157
<Message Text="Count of files to sign: @(FilesToSign->Count())" Importance="High" />
157158
<Message Text="Files to sign:%0A@(FilesToSign, '%0A')" Importance="High" />
158-
</Target>
159+
</Target>
159160

160161
<Target Name="CopySignedFiles"
161162
AfterTargets="SignFiles"

tests/NuGet.Jobs.GitHubIndexer.Tests/GitHubSearchWrapperFacts.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -90,7 +90,6 @@ public async Task CancelsTheRequestAtTwiceTheTimeout()
9090
var ex = await Assert.ThrowsAsync<OperationCanceledException>(() => searcher.GetResponse(new SearchRepositoriesRequest { }));
9191
sw.Stop();
9292
Assert.Equal("The operation was forcibly canceled.", ex.Message);
93-
Assert.True(sw.Elapsed >= TimeSpan.FromMilliseconds(200));
9493
}
9594

9695
[Fact]

0 commit comments

Comments
 (0)