Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enable Unpacking, repacking, signing, and notarization of .pkg files and .app bundles #15206

Merged
merged 88 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
404f889
Integrate Pkg Tool into SignTool
ellahathaway Oct 29, 2024
764e87f
Merge branch 'main' of https://github.com/dotnet/arcade into signtool…
ellahathaway Nov 21, 2024
e278e73
Change name to MacOSPkg
ellahathaway Nov 21, 2024
5bba3de
Rename repack to pack
ellahathaway Nov 21, 2024
73a862d
Re-add netframework targeting for Tools.proj PackageRef compat
mmitche Nov 22, 2024
4c34a11
Update src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj
mmitche Nov 22, 2024
dc7d4aa
Update src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj
mmitche Nov 22, 2024
c545ecc
Merge remote-tracking branch 'origin/target-netframework' into signto…
mmitche Nov 22, 2024
c41baaa
Update src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.proj
mmitche Nov 22, 2024
e5b015f
Tweaks
mmitche Nov 22, 2024
2e27d3b
Merge branch 'signtool-unpack-repack-pkg' of https://github.com/ellah…
mmitche Nov 22, 2024
65fc7bc
Sign .pkg files and .app bundles
ellahathaway Oct 29, 2024
30292d6
OSX files signing infra
mmitche Nov 22, 2024
ffe2b3b
Tweaks
mmitche Nov 22, 2024
a974f61
Only delete extract directory if it exists
mmitche Nov 22, 2024
ad3af68
Don't remove non-existent extract dir
mmitche Nov 22, 2024
9fb52c3
Fix bracing
mmitche Nov 25, 2024
ca7aee4
Change signing key for .pkg and .app
mmitche Nov 25, 2024
f532742
Throw when we fail to unpack a pkg or tar.
mmitche Nov 25, 2024
e6135ed
correct paths for tar and pkg tooling
mmitche Nov 25, 2024
8c9757a
Import TargetFrameworkDefaults
mmitche Nov 25, 2024
a4ab639
Do not pack up appbundles that are not appbundles
mmitche Nov 26, 2024
49d9891
Debugging
mmitche Dec 2, 2024
964511c
Replace strong name verification with custom implementation
mmitche Dec 5, 2024
4d17839
Fix casing of resource
mmitche Dec 6, 2024
74522cb
Merge remote-tracking branch 'upstream/main' into add-in-osx-files-si…
mmitche Dec 9, 2024
94a38e4
Merge remote-tracking branch 'upstream/main' into add-in-osx-files-si…
mmitche Dec 9, 2024
f9c6528
Merge branch 'replace-sn-with-custom-implementation' into add-in-osx-…
mmitche Dec 9, 2024
a00fe45
Fix merge
mmitche Dec 9, 2024
1cb5f46
Merge remote-tracking branch 'upstream/main' into add-in-osx-files-si…
mmitche Dec 10, 2024
77ee388
Do not skip local strong name signing in local validation
mmitche Dec 10, 2024
ee330fb
Switch back to file name
mmitche Dec 10, 2024
ee18602
Improve error reporting
mmitche Dec 10, 2024
9727717
Support verification with the ecma key
mmitche Dec 11, 2024
da162f0
Support verification with the ecma key
mmitche Dec 11, 2024
94e5922
Temporarily do not remove public sign
mmitche Dec 11, 2024
a753b93
Fix log messages for strong name signature status
mmitche Dec 11, 2024
3778f7a
Merge remote-tracking branch 'origin/replace-sn-with-custom-implement…
mmitche Dec 12, 2024
59d4101
Enable signing
mmitche Dec 17, 2024
8df4bb5
Refactoring
mmitche Dec 17, 2024
7dfbe69
Remove public key
mmitche Dec 17, 2024
c110331
Add codeql annotations
mmitche Dec 17, 2024
abe8e49
This test should have been skipped
mmitche Dec 17, 2024
a0c3185
WindowsOnlyFact
mmitche Dec 18, 2024
a73314d
Update src/Microsoft.DotNet.SignTool/src/StrongName.cs
mmitche Dec 18, 2024
1201139
Update src/Microsoft.DotNet.SignTool/src/StrongName.cs
mmitche Dec 18, 2024
dc69aec
Omit unneeded algo sub ids
mmitche Dec 18, 2024
f637e9f
Merge remote-tracking branch 'origin/replace-sn-with-custom-implement…
mmitche Dec 18, 2024
e48b5ca
Merge branch 'main' into replace-sn-with-custom-implementation
mmitche Dec 18, 2024
7a25623
Merge branch 'replace-sn-with-custom-implementation' into add-in-osx-…
mmitche Dec 18, 2024
7c37fb3
Add logging back to LocalStrongNameSign
mmitche Dec 18, 2024
d4552a3
Add logging back to LocalStrongNameSign
mmitche Dec 18, 2024
cb0fe15
Avoid excluding files on non-Windows
mmitche Dec 18, 2024
6ab9815
Avoid excluding files on non-Windows
mmitche Dec 18, 2024
9678b01
Improve logging
mmitche Dec 31, 2024
b654cab
Generate microbuild project file properly for already strong named files
mmitche Dec 31, 2024
f3b4f51
Use PackageDownload instead of PackageRef for sn.exe
mmitche Jan 2, 2025
408530b
Merge branch 'main' into replace-sn-with-custom-implementation
mmitche Jan 2, 2025
8c99d92
Pass log at IsSigned callsite
mmitche Jan 2, 2025
4425ec8
Merge remote-tracking branch 'origin/replace-sn-with-custom-implement…
mmitche Jan 2, 2025
fb20ca6
Do not error if strong name check is set and sn.exe is not available
mmitche Jan 2, 2025
05481ef
Merge remote-tracking branch 'origin/replace-sn-with-custom-implement…
mmitche Jan 2, 2025
2807f6b
Make args explicit
mmitche Jan 2, 2025
b64af02
Make args explicit
mmitche Jan 2, 2025
1c0b5fc
Merge remote-tracking branch 'upstream/main' into add-in-osx-files-si…
mmitche Jan 3, 2025
5c76be4
Tweak osx signing
mmitche Jan 3, 2025
5904603
Use command line parser for the pkg tool
mmitche Jan 7, 2025
4efaa6d
Add notarization
mmitche Jan 7, 2025
4fc9125
Refactor signtool a bit and add notarization support
mmitche Jan 8, 2025
cc4c40b
Fixup Mac tests
mmitche Jan 8, 2025
49474a0
Fixup notarization project
mmitche Jan 9, 2025
02cb2fb
Unzip before notarization
mmitche Jan 9, 2025
1e68feb
Self review feedback
mmitche Jan 14, 2025
a9fdf13
Refactoring
mmitche Jan 14, 2025
a7ce588
Refactoring and fixup publishing
mmitche Jan 14, 2025
874a716
Merge remote-tracking branch 'upstream/main' into signtool-unpack-rep…
mmitche Jan 14, 2025
ddc6414
Merge remote-tracking branch 'upstream/main' into signtool-unpack-rep…
mmitche Jan 14, 2025
e757f6a
Fixup build errors
mmitche Jan 14, 2025
34e3b5b
Fixup test after merge
mmitche Jan 14, 2025
64e43fc
Self-feedback
mmitche Jan 15, 2025
8da94d4
Fix tests
mmitche Jan 15, 2025
6d0e24e
Merge remote-tracking branch 'upstream/main' into signtool-unpack-rep…
mmitche Jan 15, 2025
7418f85
Apply suggestions from code review
mmitche Jan 15, 2025
29bab8c
Build fixes
mmitche Jan 15, 2025
5ef3ba2
Merge branch 'signtool-unpack-repack-pkg' of https://github.com/ellah…
mmitche Jan 15, 2025
74a4ceb
Build fixes
mmitche Jan 15, 2025
4376330
Switch to tri-state signing status, and do some more refactoring
mmitche Jan 16, 2025
379f61d
Change method names
mmitche Jan 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions Arcade.sln
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Build.Task
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.RemoteExecutor.Tests", "src\Microsoft.DotNet.RemoteExecutor\tests\Microsoft.DotNet.RemoteExecutor.Tests.csproj", "{D6AC20A4-1719-49FE-B112-B2AB564496F8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestProjects", "TestProjects", "{6F517597-E9E2-43B2-B7E2-757132EA525C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Build.Tasks.Archives", "src\Microsoft.DotNet.Build.Tasks.Archives\Microsoft.DotNet.Build.Tasks.Archives.csproj", "{5579768A-CC07-477C-ACE4-06FE9B0686A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.SourceBuild.Tasks", "src\Microsoft.DotNet.SourceBuild\tasks\Microsoft.DotNet.SourceBuild.Tasks.csproj", "{F9D72AF5-9320-43C8-A24F-CBE294FCED0A}"
Expand Down Expand Up @@ -129,10 +127,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Build.Task
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Build.Tasks.Templating.Tests", "src\Microsoft.DotNet.Build.Tasks.Templating\test\Microsoft.DotNet.Build.Tasks.Templating.Tests.csproj", "{FB4168D5-6EA6-4777-AD4F-95758C177FE8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6DA9F58A-34D5-45A6-998E-5D2B8037C3FE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.DotNet.XUnitAssert", "Microsoft.DotNet.XUnitAssert", "{3C542789-2576-48C8-9772-C9D7575F7E42}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.XUnitAssert", "src\Microsoft.DotNet.XUnitAssert\src\Microsoft.DotNet.XUnitAssert.csproj", "{AB8D5F86-60FA-416A-B047-83B1E9118425}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.XUnitAssert.Tests", "src\Microsoft.DotNet.XUnitAssert\tests\Microsoft.DotNet.XUnitAssert.Tests.csproj", "{14462553-E4E1-4F67-B954-4BF24B1DAAFE}"
Expand All @@ -151,9 +145,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Internal.S
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.ArcadeAzureIntegration", "src\Microsoft.DotNet.ArcadeAzureIntegration\Microsoft.DotNet.ArcadeAzureIntegration.csproj", "{CA159C84-CD7D-4364-9121-3842F97D4B60}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DotNet.MacOsPkg", "src\Microsoft.DotNet.MacOsPkg\Microsoft.DotNet.MacOsPkg.csproj", "{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.MacOsPkg", "src\Microsoft.DotNet.MacOsPkg\Microsoft.DotNet.MacOsPkg.csproj", "{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DotNet.MacOsPkg.Tests", "src\Microsoft.DotNet.MacOsPkg.Tests\Microsoft.DotNet.MacOsPkg.Tests.csproj", "{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.MacOsPkg.Tests", "src\Microsoft.DotNet.MacOsPkg.Tests\Microsoft.DotNet.MacOsPkg.Tests.csproj", "{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -1009,13 +1003,10 @@ Global
{B5E9D9D8-59E0-49F8-9C3C-75138A2D452C} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{0B5D3C20-EB58-4A82-A3AA-2E626A17B35D} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{FB4168D5-6EA6-4777-AD4F-95758C177FE8} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{3C542789-2576-48C8-9772-C9D7575F7E42} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE}
{AB8D5F86-60FA-416A-B047-83B1E9118425} = {3C542789-2576-48C8-9772-C9D7575F7E42}
{14462553-E4E1-4F67-B954-4BF24B1DAAFE} = {3C542789-2576-48C8-9772-C9D7575F7E42}
{14462553-E4E1-4F67-B954-4BF24B1DAAFE} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{650B7526-7B8A-45B5-B14E-C16D828891B2} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{6BA81447-C61D-4F91-BF0F-5B17AF4CFFAC} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE}
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE}
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45} = {C53DD924-C212-49EA-9BC4-1827421361EF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {32B9C883-432E-4FC8-A1BF-090EB033DD5B}
Expand Down
7 changes: 6 additions & 1 deletion src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.proj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
</PropertyGroup>

<Import Project="BuildStep.props" />
<Import Project="TargetFrameworkDefaults.props" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this import being used anywhere below. I don't think that the Arcade TFM properties can be used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I had this in there to use NetToolCurrent for the command line tools. Updated


<Import Project="$(NuGetPackageRoot)microsoft.dotnet.signtool\$(MicrosoftDotNetSignToolVersion)\build\Microsoft.DotNet.SignTool.props" />

Expand Down Expand Up @@ -57,6 +58,9 @@

<!-- SN is only available on Windows -->
<SNBinaryPath Condition="$([MSBuild]::IsOSPlatform('Windows'))">$(NuGetPackageRoot)sn\$(SNVersion)\sn.exe</SNBinaryPath>

<!-- .pkgs and .app bundle tooling is only available on MacOS -->
<PkgToolPath Condition="$([MSBuild]::IsOSPlatform('OSX'))">$(NuGetPackageRoot)microsoft.dotnet.macospkg\$(MicrosoftDotNetMacOsPkgVersion)\tools\$(NetToolCurrent)\any\Microsoft.Dotnet.MacOsPkg.dll</PkgToolPath>
</PropertyGroup>

<Error Condition="'$(AllowEmptySignList)' != 'true' AND '@(ItemsToSign)' == ''"
Expand All @@ -83,7 +87,8 @@
SNBinaryPath="$(SNBinaryPath)"
MicroBuildCorePath="$(NuGetPackageRoot)microbuild.core\$(MicroBuildCoreVersion)"
WixToolsPath="$(WixInstallPath)"
TarToolPath="$(NuGetPackageRoot)microsoft.dotnet.tar\$(MicrosoftDotNetSignToolVersion)\tools\net10.0\any\Microsoft.Dotnet.Tar.dll"
TarToolPath="$(NuGetPackageRoot)microsoft.dotnet.tar\$(MicrosoftDotNetTarVersion)\tools\$(NetToolCurrent)\any\Microsoft.Dotnet.Tar.dll"
PkgToolPath="$(PkgToolPath)"
RepackParallelism="$(SignToolRepackParallelism)"
MaximumParallelFileSize="$(SignToolRepackMaximumParallelFileSize)" />
</Target>
Expand Down
14 changes: 12 additions & 2 deletions src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
<ItemGroup>
<!--
This is intended to hold information about the certificates used for signing.
For now the only information required is whether or not the certificate can be
used for signing already signed files - DualSigningAllowed==true.
-->
<CertificatesSignInfo Include="3PartyDual" DualSigningAllowed="true" />
<CertificatesSignInfo Include="3PartySHA2" DualSigningAllowed="true" />
<!-- This signing information indicates certificates that represent a sign and notarize operation. -->
<CertificatesSignInfo Include="MacDeveloperHardenWithNotarization" MacCertificate="MacDeveloperHarden" MacNotarizationAppName="dotnet" />
<CertificatesSignInfo Include="MacDeveloperWithNotarization" MacCertificate="MacDeveloper" MacNotarizationAppName="dotnet" />
<CertificatesSignInfo Include="MacDeveloperVNextWithNotarization" MacCertificate="MacDeveloperVNext" MacNotarizationAppName="dotnet" />
<CertificatesSignInfo Include="MacDeveloperVNextHardenWithNotarization" MacCertificate="MacDeveloperVNextHarden" MacNotarizationAppName="dotnet" />
</ItemGroup>

<ItemGroup Condition="'$(EnableDefaultArtifacts)' == 'true'">
Expand Down Expand Up @@ -60,6 +63,13 @@
<FileExtensionSignInfo Include=".zip" CertificateName="None" />
<FileExtensionSignInfo Include=".tgz" CertificateName="None" />
<FileExtensionSignInfo Include=".tar.gz" CertificateName="None" />
<!-- Note, these can only be unpack/repacked on Mac. They can be signed on a non-Mac -->
<FileExtensionSignInfo Include=".pkg" CertificateName="MacDeveloper" />
<!-- .app bundles are technically directories, but the Microsoft.DotNet.MacOsPkg
tool packs these bundles into zips when unpacking .pkgs -->
<FileExtensionSignInfo Include=".app" CertificateName="MacDeveloper" />
<!-- Runtime hardening is required for notarization. -->
<FileExtensionSignInfo Include=".dylib" CertificateName="MacDeveloperHarden" />
</ItemGroup>

<!-- The name of the .NET specific certificate, which is a general replacement for Microsoft400
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,11 @@ public void RoundTripFromTaskItemsToFileToXml()
new TaskItem("MyOtherCert", new Dictionary<string, string>()
{
{ "DualSigningAllowed", "true" }
}),
new TaskItem("MySpecialCert", new Dictionary<string, string>()
{
{ "MacCertificate", "MacMac" },
{ "MacNotarizationAppName", "dotnet" }
})
};

Expand Down Expand Up @@ -522,11 +527,22 @@ public void RoundTripFromTaskItemsToFileToXml()
{
item.Include.Should().Be("MyCert");
item.DualSigningAllowed.Should().Be(false);
item.MacCertificate.Should().BeNullOrEmpty();
item.MacNotarizationAppName.Should().BeNullOrEmpty();
},
item =>
{
item.Include.Should().Be("MyOtherCert");
item.DualSigningAllowed.Should().Be(true);
item.MacCertificate.Should().BeNullOrEmpty();
item.MacNotarizationAppName.Should().BeNullOrEmpty();
},
item =>
{
item.Include.Should().Be("MySpecialCert");
item.DualSigningAllowed.Should().Be(false);
item.MacCertificate.Should().Be("MacMac");
item.MacNotarizationAppName.Should().Be("dotnet");
});
modelFromFile.SigningInformation.FileExtensionSignInfo.Should().SatisfyRespectively(
item =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.DotNet.VersionTools.BuildManifest.Model;
using Microsoft.DotNet.VersionTools.Util;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -101,7 +102,11 @@ public SigningInformationModel CreateSigningInformationModelFromItems(
foreach (var signInfo in certificatesSignInfo)
{
var attributes = signInfo.CloneCustomMetadata() as IDictionary<string, string>;
parsedCertificatesSignInfoModel.Add(new CertificatesSignInfoModel { Include = signInfo.ItemSpec, DualSigningAllowed = bool.Parse(attributes["DualSigningAllowed"]) });
parsedCertificatesSignInfoModel.Add(new CertificatesSignInfoModel { Include = signInfo.ItemSpec,
DualSigningAllowed = bool.Parse(attributes.GetOrDefault("DualSigningAllowed") ?? "false"),
MacCertificate = attributes.GetOrDefault("MacCertificate"),
MacNotarizationAppName = attributes.GetOrDefault("MacNotarizationAppName"),
});
}
}

Expand Down
48 changes: 48 additions & 0 deletions src/Microsoft.DotNet.MacOsPkg/AppBundle.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,49 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.IO;

namespace Microsoft.DotNet.MacOsPkg
{
internal static class AppBundle
{
/// <summary>
/// Determine whether a path is an app bundle.
///
/// A path an app bundle if:
/// - It's a directory and ends in .app and contains a Contents directory and that contains an Info.plist file.
/// - It's a file and ends in .app.
/// </summary>
/// <param name="path">Path to check</param>
/// <returns>True if this is an app bundle, false otherwise</returns>
internal static bool IsBundle(string path)
{
if (Directory.Exists(path))
{
// Case sensitive check for .app extension is intentional.
if (Path.GetExtension(path) == ".app")
{
bool containsAppBundleContents = Directory.Exists(Path.Combine(path, "Contents")) &&
File.Exists(Path.Combine(path, "Contents", "Info.plist"));
if (!containsAppBundleContents)
{
// If we hit this, and it is a valid app bundle, then we should adjust the logic above.
// If we never hit this (likely), then remove.
throw new Exception("Unexpected .app directory structure. Please contact dnceng.");
}
return containsAppBundleContents;
}
}
else
{
return Path.GetExtension(path) == ".app";
}

return false;
}

internal static void Unpack(string inputPath, string outputPath)
{
string args = $"-V -xk {inputPath} {outputPath}";
Expand All @@ -16,5 +55,14 @@ internal static void Pack(string inputPath, string outputPath)
string args = $"-c -k --sequesterRsrc {inputPath} {outputPath}";
ExecuteHelper.Run("ditto", args);
}

internal static void VerifySignature(string inputPath)
{
string output = ExecuteHelper.Run("codesign", $"--verify --verbose {inputPath}");
if (output.Contains("is not signed at all"))
{
throw new Exception("No signature found in app bundle");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<DevelopmentDependency>false</DevelopmentDependency>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" />
</ItemGroup>

<PropertyGroup Condition="'$(TargetFramework)' == '$(NetToolCurrent)'">
<PackAsTool>true</PackAsTool>
<ToolCommandName>dotnet-macos-pkg</ToolCommandName>
Expand Down
41 changes: 39 additions & 2 deletions src/Microsoft.DotNet.MacOsPkg/Package.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,37 @@ private static void UnpackInstallerPackage(string dstPath, string distribution)
}
}

/// <summary>
/// Unpack the payload of the .pkg, and package up .app directories as .zips
/// </summary>
/// <param name="dstPath"></param>
/// <remarks>
/// In a pkg, the .app bundles are represented by directories with a standard file structure.
/// The directory is typically marked with a .app extension, though apparently this is not required.
/// The important part is that the .app bundle is viewed by the system as a single entity and is signed as such.
/// This means that signtool needs to view the .app as a signable file and not as a directory. To achieve this,
/// After unpacking the payload, we zip the .app directories so that signtool can properly track them, unpack them recursively again,
/// and sign them.
///
/// There's one other important element to this. We need to recognize whether the .app directory is in fact
/// a .app bundle and not, say "Microsoft.NetCore.App". To do this, we apply some heuristics.
/// If:
/// - Extension should be lower case ".app"
/// - A directory named "Contents" under the .app directory.
/// - An Info.plist in this "Contents" directory.
///
/// If these conditions are met, the file is re-zipped and treated like a bundle.
///
/// NOTE: I believe that there are very no circumstances where the first condition is met but the other two
/// will NOT be met. For now, this method will throw an exception in this case so that further examination can be
/// made.
/// </remarks>
private static void UnpackComponentPackage(string dstPath)
{
UnpackPayload(dstPath);

// Zip the nested app bundles
IEnumerable<string> nestedApps = Directory.GetDirectories(dstPath, "*.app", SearchOption.AllDirectories);
IEnumerable<string> nestedApps = Directory.GetDirectories(dstPath, "*.app", SearchOption.AllDirectories).Where(app => AppBundle.IsBundle(app));
foreach (string app in nestedApps)
{
string tempDest = $"{app}.zip";
Expand Down Expand Up @@ -117,7 +142,7 @@ private static void PackInstallerPackage(string srcPath, string dstPath, string
private static void PackComponentPackage(string srcPath, string dstPath, string packageInfo)
{
// Unzip the nested app bundles
IEnumerable<string> zippedNestedApps = Directory.GetFiles(srcPath, "*.app", SearchOption.AllDirectories);
IEnumerable<string> zippedNestedApps = Directory.GetFiles(srcPath, "*.app", SearchOption.AllDirectories).Where(app => AppBundle.IsBundle(app));
foreach (string appZip in zippedNestedApps)
{
// Unzip the .app directory
Expand Down Expand Up @@ -175,5 +200,17 @@ private static void ExpandPackage(string srcPath, string dstPath) =>

private static string GetPackageInfoAttribute(XElement pkgInfo, string elementName) =>
pkgInfo.Attribute(elementName)?.Value ?? throw new Exception($"{elementName} is required in PackageInfo");

internal static void VerifySignature(string inputPath)
{
Console.WriteLine($"Verifying signature of {inputPath}");
string full_path = Path.GetFullPath(inputPath);
string output = ExecuteHelper.Run("pkgutil", $"--check-signature {full_path}");
Console.WriteLine(output);
if (output.Contains("Status: no signature"))
{
throw new Exception("No signature found in package");
}
}
}
}
Loading
Loading