Embed entitlements
Embed .entitlements directly in your executable binary.
Motivation
On Apple platforms (macOS, iOS, tvOS, watchOS and visionOS), applications are sandboxed (optionally on macOS, required on the others). Granting your application additional capabilities to functionality outside the sandbox is controlled using "entitlements", see Apple's documentation.
Usually, these are applied when code signing, such as by resigning a binary in the following manner:
For binaries that run on the simulator (Simulator.app / xcrun simctl),
things are a bit different though; the binary runs on the host macOS XNU
kernel, which means that the binary's entitlements are applied in a macOS
context. So you don't want to sign it with iOS entitlements (at a maximum, you
want to sign it with the com.apple.security.get-task-allow entitlement).
Instead, the entitlements that the simulator should apply is embedded inside
the binary in the __TEXT,__entitlements section.
Xcode does this automatically by invoking the linker with -sectcreate, but
if you want to run your binary on the simulator without building it in Xcode,
you can use this crate to do the embedding.
This crate works well with the embed_plist
crate for embedding an application's Info.plist.
Simulator usage
Add the embed_entitlements crate when your project is compiled for a
simulator target:
Write the desired entitlements to a file (in this example
keychain.entitlements):
keychain-access-groups
com.somecompany.testgroup
And tell embed_entitlements to embed that file in your binary:
embed_entitlements!;
General usage
Annoyingly, this separation between entitlements on real devices and in the simulator means that you have to mention the entitlement file in multiple places.
Ideally, you would just be able to write:
embed_entitlements!;
And have that work regardless of whether you're compiling for the simulator or a real device.
Projects that bundle and sign applications can make this work though! All they have to do is something like the following:
let file = parse.unwrap;
if let Some = file.section_by_name
&& target.env != "sim"
else
Current the following projects support this usage:
- None.
See #2 for tracking doing this in the Rust ecosystem.
DER
On newer OS versions, the simulator actually reads from __TEXT,__ents_der,
which contains the entitlement re-encoded in DER / ASN.1 format, see
this tech note
for details.
On target_env = "sim", this crate automatically converts the entitlements
file to DER and also embeds that in the __TEXT,__ents_der section. This
requires a procedural macro.
Multi-use protection
Only one entitlement file can exist in a binary, and accidentally embedding it multiple times would break in weird ways. This library makes reuse a link-time error, which means the error happens even if the macro is used across different crates and modules.
embed_entitlements::embed_entitlements!("keychain.entitlements");
embed_entitlements::embed_entitlements!("keychain.entitlements");
This example produces an error like this:
error: symbol `_EMBED_ENTITLEMENT` is already defined
--> srcmain.rs
|
| embed_entitlements::embed_entitlements!("keychain.entitlements");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Minimum Supported Rust Version
This library targets 1.91 as its minimum supported Rust version (MSRV),
because it uses target_env = "sim". This could possibly be lowered if need
be, feel free to open an issue if you need it.
License
This project is trio-licensed under the Zlib, Apache-2.0 or MIT license, at your option.