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

[msbuild] Sign simulator apps by default. Fixes #18469. #19544

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
23d062b
[msbuild] Sign simulator apps by default. Fixes #18469.
rolfbjarne Nov 20, 2023
1b8bf9b
[tests] Update msbuild tests.
rolfbjarne Nov 29, 2023
e8ded9a
[tests] Update test.
rolfbjarne Nov 29, 2023
bb08532
[msbuild] Simplified entitlements for the simulator.
rolfbjarne Jun 7, 2024
b3c66b6
[msbuild] Silence warnings app developers can't silence themselves.
rolfbjarne Jun 10, 2024
9266820
Merge remote-tracking branch 'origin/main' into codesign-simulator-by…
rolfbjarne Jun 10, 2024
71e95a3
[tests] We can no longer symlink simulator apps, so 'static' is the d…
rolfbjarne Jun 10, 2024
a78800a
Try something new.
rolfbjarne Jun 11, 2024
c315807
Auto-format source code
Jun 11, 2024
6f013af
This snowballed a bit...
rolfbjarne Jun 11, 2024
88cd914
Merge remote-tracking branch 'origin/main' into codesign-simulator-by…
rolfbjarne Jun 12, 2024
2b472ae
Merge remote-tracking branch 'origin/main' into codesign-simulator-by…
rolfbjarne Jun 17, 2024
7068766
[msbuild] Only show warning when not in the simulator.
rolfbjarne Jun 17, 2024
e916a69
Only mobile entitlements
rolfbjarne Jun 17, 2024
5bd1b18
Auto-format source code
Jun 17, 2024
94a2d12
Fix condition
rolfbjarne Jun 18, 2024
6252830
Fix condition for a second time.
rolfbjarne Jun 19, 2024
12fdfa6
[tests] Remove the symlink mono-native mode.
rolfbjarne Jun 19, 2024
09e0700
[msbuild] Fix computing which items need code signing.
rolfbjarne Jun 19, 2024
1ea22d0
Merge remote-tracking branch 'origin/main' into codesign-simulator-by…
rolfbjarne Jun 20, 2024
64f80ee
Simplify
rolfbjarne Jun 20, 2024
7ea14cd
Merge remote-tracking branch 'origin/main' into codesign-simulator-by…
rolfbjarne Jun 25, 2024
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
11 changes: 9 additions & 2 deletions msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1560,9 +1560,16 @@
<comment>0: a path</comment>
</data>

<data name="E7124" xml:space="preserve">
<data name="W7124" xml:space="preserve">
<value>A provisioning profile has been specified, but this value is ignored for the simulator.</value>
</data>

<data name="W7125" xml:space="preserve">
<value>A file with codesigning entitlements has been specified, but this value is ignored for the simulator.</value>
</data>

<data name="E7126" xml:space="preserve">
<value>Can't compute the architecture for the archive for the RuntimeIdentifier '{0}' (unknown value)</value>
<comment>RuntimeIdentifier: don't translate (it's the name of a MSBuild property)</comment>
</data>

</root>
2 changes: 1 addition & 1 deletion msbuild/Xamarin.MacDev.Tasks/Tasks/Archive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public override bool Execute ()
} else if (rid.EndsWith ("-arm64", StringComparison.Ordinal)) {
architecture = "arm64";
} else {
Log.LogError (MSBStrings.E7124 /* Can't compute the architecture for the archive for the RuntimeIdentifier '{0}' (unknown value) */, rid);
Log.LogError (MSBStrings.E7126 /* Can't compute the architecture for the archive for the RuntimeIdentifier '{0}' (unknown value) */, rid);
continue;
}
array.Add (new PString (architecture));
Expand Down
5 changes: 4 additions & 1 deletion msbuild/Xamarin.MacDev.Tasks/Tasks/Codesign.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,11 @@ bool ExecuteUnsafe ()
var info = new SignInfo { Item = item };
if (!Validate (info))
continue;
if (NeedsCodesign (resourcesToSign, i, info.GetStampFileContents (this)))
if (NeedsCodesign (resourcesToSign, i, info.GetStampFileContents (this))) {
itemsToSign.Add (info);
} else {
resourcesToSign [i] = null;
}
}

if (Log.HasLoggedErrors)
Expand Down
93 changes: 61 additions & 32 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,22 +138,38 @@ protected string EntitlementBundlePath {
}
}

PString MergeEntitlementString (PString pstr, MobileProvision? profile, bool expandWildcards)
bool IsDeviceOrDesktop {
get {
switch (Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
case ApplePlatform.WatchOS:
return !SdkIsSimulator;
case ApplePlatform.MacOSX:
case ApplePlatform.MacCatalyst:
return true;
default:
throw new InvalidOperationException (string.Format (MSBStrings.InvalidPlatform, Platform));
}
}
}

PString MergeEntitlementString (PString pstr, MobileProvision? profile, bool expandWildcards, string? key)
{
string TeamIdentifierPrefix;
string AppIdentifierPrefix;

if (string.IsNullOrEmpty (pstr.Value))
return (PString) pstr.Clone ();

if (profile is null) {
if (profile is null && IsDeviceOrDesktop) {
if (!warnedTeamIdentifierPrefix && pstr.Value.Contains ("$(TeamIdentifierPrefix)")) {
Log.LogWarning (null, null, null, Entitlements, 0, 0, 0, 0, MSBStrings.W0108);
Log.LogWarning (null, null, null, Entitlements, 0, 0, 0, 0, "Cannot expand $(TeamIdentifierPrefix) in Entitlements.plist without a provisioning profile for key '{0}' with value '{1}'", key, pstr.Value);
warnedTeamIdentifierPrefix = true;
}

if (!warnedAppIdentifierPrefix && pstr.Value.Contains ("$(AppIdentifierPrefix)")) {
Log.LogWarning (null, null, null, Entitlements, 0, 0, 0, 0, MSBStrings.W0109);
Log.LogWarning (null, null, null, Entitlements, 0, 0, 0, 0, "Cannot expand $(AppIdentifierPrefix) in Entitlements.plist without a provisioning profile for key '{0}' with value '{1}'", key, pstr.Value);
warnedAppIdentifierPrefix = true;
}
}
Expand Down Expand Up @@ -198,19 +214,19 @@ PString MergeEntitlementString (PString pstr, MobileProvision? profile, bool exp
return new PString (expanded);
}

PArray? MergeEntitlementArray (PArray array, MobileProvision? profile)
PArray? MergeEntitlementArray (PArray array, MobileProvision? profile, string? key)
{
var result = new PArray ();

foreach (var item in array) {
PObject? value;

if (item is PDictionary)
value = MergeEntitlementDictionary ((PDictionary) item, profile);
value = MergeEntitlementDictionary ((PDictionary) item, profile, key);
else if (item is PString)
value = MergeEntitlementString ((PString) item, profile, false);
value = MergeEntitlementString ((PString) item, profile, false, key);
else if (item is PArray)
value = MergeEntitlementArray ((PArray) item, profile);
value = MergeEntitlementArray ((PArray) item, profile, key);
else
value = item.Clone ();

Expand All @@ -224,19 +240,19 @@ PString MergeEntitlementString (PString pstr, MobileProvision? profile, bool exp
return null;
}

PDictionary MergeEntitlementDictionary (PDictionary dict, MobileProvision? profile)
PDictionary MergeEntitlementDictionary (PDictionary dict, MobileProvision? profile, string? key)
{
var result = new PDictionary ();

foreach (var item in dict) {
PObject? value = item.Value;

if (value is PDictionary)
value = MergeEntitlementDictionary ((PDictionary) value, profile);
value = MergeEntitlementDictionary ((PDictionary) value, profile, item.Key);
else if (value is PString)
value = MergeEntitlementString ((PString) value, profile, false);
value = MergeEntitlementString ((PString) value, profile, false, item.Key);
else if (value is PArray)
value = MergeEntitlementArray ((PArray) value, profile);
value = MergeEntitlementArray ((PArray) value, profile, item.Key);
else
value = value.Clone ();

Expand Down Expand Up @@ -286,7 +302,7 @@ void AddCustomEntitlements (PDictionary dict, MobileProvision? profile)
dict [entitlement] = new PBoolean (booleanValue);
break;
case "string":
dict [entitlement] = MergeEntitlementString (new PString (value), profile, entitlement == ApplicationIdentifierKey);
dict [entitlement] = MergeEntitlementString (new PString (value), profile, entitlement == ApplicationIdentifierKey, entitlement);
break;
case "stringarray":
var arraySeparator = item.GetMetadata ("ArraySeparator");
Expand All @@ -295,7 +311,7 @@ void AddCustomEntitlements (PDictionary dict, MobileProvision? profile)
var arrayContent = value.Split (new string [] { arraySeparator }, StringSplitOptions.None);
var parray = new PArray ();
foreach (var element in arrayContent)
parray.Add (MergeEntitlementString (new PString (element), profile, entitlement == ApplicationIdentifierKey));
parray.Add (MergeEntitlementString (new PString (element), profile, entitlement == ApplicationIdentifierKey, entitlement));
dict [entitlement] = parray;
break;
default:
Expand Down Expand Up @@ -358,11 +374,11 @@ protected virtual PDictionary GetCompiledEntitlements (MobileProvision? profile,
if (key == "com.apple.developer.icloud-container-environment")
value = new PString ("Development");
else if (value is PDictionary)
value = MergeEntitlementDictionary ((PDictionary) value, profile);
value = MergeEntitlementDictionary ((PDictionary) value, profile, key);
else if (value is PString)
value = MergeEntitlementString ((PString) value, profile, item.Key == ApplicationIdentifierKey);
value = MergeEntitlementString ((PString) value, profile, item.Key == ApplicationIdentifierKey, key);
else if (value is PArray)
value = MergeEntitlementArray ((PArray) value, profile);
value = MergeEntitlementArray ((PArray) value, profile, key);
else
value = value.Clone ();

Expand Down Expand Up @@ -393,11 +409,11 @@ protected virtual PDictionary GetCompiledEntitlements (MobileProvision? profile,
}

if (value is PDictionary)
value = MergeEntitlementDictionary ((PDictionary) value, profile);
value = MergeEntitlementDictionary ((PDictionary) value, profile, key);
else if (value is PString)
value = MergeEntitlementString ((PString) value, profile, key == ApplicationIdentifierKey);
value = MergeEntitlementString ((PString) value, profile, key == ApplicationIdentifierKey, key);
else if (value is PArray)
value = MergeEntitlementArray ((PArray) value, profile);
value = MergeEntitlementArray ((PArray) value, profile, key);
else
value = value.Clone ();

Expand Down Expand Up @@ -456,7 +472,7 @@ public override bool Execute ()
MobileProvision? profile;
PDictionary template;
PDictionary compiled;
PDictionary archived;
PDictionary? archived = null;
string path;

switch (SdkPlatform) {
Expand Down Expand Up @@ -509,7 +525,27 @@ public override bool Execute ()
}

compiled = GetCompiledEntitlements (profile, template);
archived = GetArchivedExpandedEntitlements (template, compiled);

Directory.CreateDirectory (Path.GetDirectoryName (CompiledEntitlements!.ItemSpec));

if (SdkIsSimulator) {
var simulatedEntitlements = compiled;
var simulatedXcent = Path.ChangeExtension (CompiledEntitlements.ItemSpec, "").TrimEnd ('.') + "-Simulated.xcent";
try {
WriteXcent (simulatedEntitlements, simulatedXcent);
} catch (Exception ex) {
Log.LogError (MSBStrings.E0114, simulatedXcent, ex.Message);
return false;
}

EntitlementsInExecutable = new TaskItem (simulatedXcent);

// No matter what, I've only been able to make Xcode apply a single entitlement to simulator builds: com.apple.security.get-task-allow
compiled = new PDictionary ();
compiled.Add ("com.apple.security.get-task-allow", new PBoolean (true));
} else {
archived = GetArchivedExpandedEntitlements (template, compiled);
}

try {
Directory.CreateDirectory (Path.GetDirectoryName (CompiledEntitlements!.ItemSpec));
Expand All @@ -519,17 +555,10 @@ public override bool Execute ()
return false;
}

SaveArchivedExpandedEntitlements (archived);
if (archived is not null)
SaveArchivedExpandedEntitlements (archived);

if (Platform == Utils.ApplePlatform.MacCatalyst) {
EntitlementsInSignature = CompiledEntitlements;
} else if (SdkIsSimulator) {
if (compiled.Count > 0) {
EntitlementsInExecutable = CompiledEntitlements;
}
} else {
EntitlementsInSignature = CompiledEntitlements;
}
EntitlementsInSignature = CompiledEntitlements;

return !Log.HasLoggedErrors;
}
Expand Down
59 changes: 1 addition & 58 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -591,64 +591,7 @@ public override bool Execute ()
return !Log.HasLoggedErrors;
}
} else {
// Framework is either iOS, tvOS or watchOS
if (SdkIsSimulator) {
if (AppleSdkSettings.XcodeVersion.Major >= 8 && RequireProvisioningProfile) {
// Note: Starting with Xcode 8.0, we need to codesign iOS Simulator builds that enable Entitlements
// in order for them to run. The "-" key is a special value allowed by the codesign utility that
// allows us to get away with not having an actual codesign key.
DetectedCodeSigningKey = "-";

if (!IsAutoCodeSignProfile (ProvisioningProfile)) {
identity.Profile = MobileProvisionIndex.GetMobileProvision (platform, ProvisioningProfile);

if (identity.Profile is null) {
Log.LogError (MSBStrings.E0140, PlatformName, ProvisioningProfile);
return false;
}

identity.AppId = ConstructValidAppId (identity.Profile, identity.BundleId);
if (identity.AppId is null) {
Log.LogError (MSBStrings.E0141, identity.BundleId, ProvisioningProfile);
return false;
}

provisioningProfileName = identity.Profile.Name;

DetectedProvisioningProfile = identity.Profile.Uuid;
DetectedDistributionType = identity.Profile.DistributionType.ToString ();
} else {
certs = new X509Certificate2 [0];

if ((profiles = GetProvisioningProfiles (platform, type, identity, certs)) is null)
return false;

if ((pairs = GetCodeSignIdentityPairs (profiles, certs)) is null)
return false;

var match = GetBestMatch (pairs, identity);
identity.Profile = match.Profile;
identity.AppId = match.AppId;

if (identity.Profile is not null) {
DetectedDistributionType = identity.Profile.DistributionType.ToString ();
DetectedProvisioningProfile = identity.Profile.Uuid;
provisioningProfileName = identity.Profile.Name;
}

DetectedAppId = identity.AppId;
}
} else {
// Note: Do not codesign. Codesigning seems to break the iOS Simulator in older versions of Xcode.
DetectedCodeSigningKey = null;
}

ReportDetectedCodesignInfo ();

return !Log.HasLoggedErrors;
}

if (!SdkIsSimulator && !RequireCodeSigning) {
if (SdkIsSimulator || !RequireCodeSigning) {
// The "-" key is a special value allowed by the codesign utility that
// allows us to get away with not having an actual codesign key.
DetectedCodeSigningKey = "-";
Expand Down
31 changes: 30 additions & 1 deletion msbuild/Xamarin.MacDev.Tasks/Tasks/LinkNativeCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ bool ExecuteUnsafe ()
foreach (var obj in ObjectFiles)
arguments.Add (Path.GetFullPath (obj.ItemSpec));

arguments.AddRange (GetEmbedEntitlementsInExecutableLinkerFlags (EntitlementsInExecutable));
arguments.AddRange (GetEmbedEntitlementsWithDerInExecutableLinkerFlags (EntitlementsInExecutable));

arguments.Add ("-o");
arguments.Add (Path.GetFullPath (OutputFile));
Expand Down Expand Up @@ -243,6 +243,20 @@ bool ExecuteUnsafe ()
return !Log.HasLoggedErrors;
}

IEnumerable<string> GetEmbedEntitlementsWithDerInExecutableLinkerFlags (string entitlements)
{
var rv = GetEmbedEntitlementsInExecutableLinkerFlags (entitlements).ToList ();
if (rv.Count > 0) {
rv.AddRange (new string [] {
"-Xlinker", "-sectcreate",
"-Xlinker", "__TEXT",
"-Xlinker", "__ents_der",
"-Xlinker", ConvertEntitlementsToDerEntitlements (Path.GetFullPath (entitlements)),
});
}
return rv;
}

public static string [] GetEmbedEntitlementsInExecutableLinkerFlags (string entitlements)
{
if (string.IsNullOrEmpty (entitlements))
Expand All @@ -259,6 +273,21 @@ public static string [] GetEmbedEntitlementsInExecutableLinkerFlags (string enti
};
}

string ConvertEntitlementsToDerEntitlements (string entitlements)
{
var derEntitlements = entitlements + ".der";
var arguments = new List<string> () {
"derq",
"query",
"-f", "xml",
"-i", entitlements,
"-o", derEntitlements,
"--raw",
};
ExecuteAsync ("xcrun", arguments, sdkDevPath: SdkDevPath).Wait ();
return derEntitlements;
}

static bool EntitlementsRequireLinkerFlags (string path)
{
try {
Expand Down
8 changes: 3 additions & 5 deletions msbuild/Xamarin.Shared/Xamarin.Shared.props
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,12 @@ Copyright (C) 2020 Microsoft. All rights reserved.
</PropertyGroup>

<!-- RequireCodeSigning -->
<!-- iOS/watchOS/tvOS is simple: device builds require code signing, simulator builds do not. This is a big lie, for some simulator builds need to be signed, but the _DetectCodeSigning task handles those cases. -->
<!-- iOS/watchOS/tvOS is simple: device builds require code signing, simulator builds technically don't even though some important features won't work unless the app is signed (launch screen won't show for instance) -->
<PropertyGroup Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
<!-- Make it possible to override the default logic by setting EnableCodeSigning -->
<_RequireCodeSigning Condition="'$(_RequireCodeSigning)' == ''">$(EnableCodeSigning)</_RequireCodeSigning>
<!-- Device builds must be signed -->
<_RequireCodeSigning Condition="'$(_RequireCodeSigning)' == '' And '$(ComputedPlatform)' == 'iPhone'">true</_RequireCodeSigning>
<!-- Otherwise code signing is disabled by default (simulator builds)-->
<_RequireCodeSigning Condition="'$(_RequireCodeSigning)' == ''">false</_RequireCodeSigning>
<!-- Device builds must be signed, and some features won't work in the simulator if the app isn't signed (launch screen for instance), so default to always sign -->
<_RequireCodeSigning Condition="'$(_RequireCodeSigning)' == ''">true</_RequireCodeSigning>
</PropertyGroup>
<!-- macOS is a bit more complicated:
* 'EnableCodeSigning' specifies whether the app is signed or not, and this defaults to false if it's not set.
Expand Down
2 changes: 1 addition & 1 deletion msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1832,7 +1832,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<Target Name="_DetectSigningIdentity" Condition="'$(_CanOutputAppBundle)' == 'true'" DependsOnTargets="$(_DetectSigningIdentityDependsOn)">
<DetectSigningIdentity
SessionId="$(BuildSessionId)"
CodesignEntitlements="$(CodesignEntitlements)"
CodesignEntitlements="$(CodesignEntitlement)"
CodesignRequireProvisioningProfile="$(CodesignRequireProvisioningProfile)"
Condition="'$(IsMacEnabled)' == 'true'"
AppBundleName="$(_AppBundleName)"
Expand Down
Loading