Skip to content

Commit

Permalink
apple-codesign: don't inherit many signing settings by default
Browse files Browse the repository at this point in the history
I think the new behavior makes more sense because it requires end-users
to opt in to settings on specific paths. This more closely approximates
how Apple's tooling works.

Closes #108.
  • Loading branch information
indygreg committed Nov 15, 2023
1 parent b272320 commit 8516e31
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 134 deletions.
11 changes: 11 additions & 0 deletions apple-codesign/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ Released on ReleaseDate.
* (Breaking change) The `--extra-digest` argument has been removed.
`--digest` can now be specified multiple times. `--digest` is now a
scoped value.
* (Breaking change) Various signing settings no longer inherit to nested
entities: `--entitlements-xml-file`, `--code-requirements-file`,
`--code-resources-file`, `--code-signature-flags`, and `--info-plist-file`.
The new behavior is much more conservative about which signing settings
can be inherited and prevents unexpected results, such as all binaries
in a bundle sharing the same entitlements or signing flags. Previous signers
of bundles may find various signing settings disappearing from nested
bundles or the non-main Mach-O binary within a bundle. It is highly encouraged
to use the `rcodesign diff-signatures` command to compare results. If settings
were dropped, add new scoped CLI arguments or use the new configuration
file feature to add settings back in to specific paths.
* (New feature) Configuration file support added. TOML based configuration
files can now define signers and signing settings in named *profiles*,
allowing for automatic and near effortless reuse of common configurations.
Expand Down
3 changes: 2 additions & 1 deletion apple-codesign/src/bundle_signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,8 @@ impl SingleBundleSigner {
let macho_data = std::fs::read(exe.absolute_path())?;
let signer = MachOSigner::new(&macho_data)?;

let mut settings = settings.clone();
let mut settings = settings
.as_bundle_main_executable_settings(exe.relative_path().to_string_lossy().as_ref());

// The identifier for the main executable is defined in the bundle's Info.plist.
if let Some(ident) = self
Expand Down
15 changes: 14 additions & 1 deletion apple-codesign/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1927,10 +1927,23 @@ enum Subcommands {
///
/// * A fat Mach-O binary will traverse into the multiple Mach-O binaries within.
/// * A bundle will traverse into nested bundles.
/// * A bundle will traverse non-code \"resource\" files and sign their digests.
/// * A bundle will traverse non-code "resource" files and sign their digests.
/// * A bundle will traverse non-main Mach-O binaries and sign them, adding their
/// metadata to the signed resources file.
///
/// When signing nested entities, only some signing settings will be copied
/// automatically:
///
/// * All settings related to the signing certificate/key.
/// * --timestamp-url
/// * --signing-time
/// * --exclude
/// * --digest
/// * --runtime-version
///
/// All other settings only apply to the main entity being signed or the
/// scoped path being annotated.
///
/// # Bundle Signing Overrides Settings
///
/// When signing bundles, some settings specified on the command line will be
Expand Down
81 changes: 74 additions & 7 deletions apple-codesign/src/signing_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ pub enum DesignatedRequirementMode {
}

/// Describes the type of a scoped setting.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ScopedSetting {
Digest,
BinaryIdentifier,
Expand All @@ -242,6 +243,30 @@ pub enum ScopedSetting {
ExtraDigests,
}

impl ScopedSetting {
pub fn all() -> &'static [Self] {
&[
Self::Digest,
Self::BinaryIdentifier,
Self::Entitlements,
Self::DesignatedRequirements,
Self::CodeSignatureFlags,
Self::RuntimeVersion,
Self::InfoPlist,
Self::CodeResources,
Self::ExtraDigests,
]
}

pub fn inherit_nested_bundle() -> &'static [Self] {
&[Self::Digest, Self::ExtraDigests, Self::RuntimeVersion]
}

pub fn inherit_nested_macho() -> &'static [Self] {
&[Self::Digest, Self::ExtraDigests, Self::RuntimeVersion]
}
}

/// Represents code signing settings.
///
/// This type holds settings related to a single logical signing operation.
Expand Down Expand Up @@ -944,13 +969,29 @@ impl<'key> SigningSettings<'key> {
/// Convert this instance to settings appropriate for a nested bundle.
#[must_use]
pub fn as_nested_bundle_settings(&self, bundle_path: &str) -> Self {
self.clone_strip_prefix(bundle_path, format!("{bundle_path}/"))
self.clone_strip_prefix(
bundle_path,
format!("{bundle_path}/"),
ScopedSetting::inherit_nested_bundle(),
)
}

/// Obtain the settings for a bundle's main executable.
#[must_use]
pub fn as_bundle_main_executable_settings(&self, path: &str) -> Self {
self.clone_strip_prefix(path, path.to_string(), ScopedSetting::all())
}

/// Convert this instance to settings appropriate for a Mach-O binary in a bundle.
///
/// Only some settings are inherited from the bundle.
#[must_use]
pub fn as_bundle_macho_settings(&self, path: &str) -> Self {
self.clone_strip_prefix(path, path.to_string())
self.clone_strip_prefix(
path,
path.to_string(),
ScopedSetting::inherit_nested_macho(),
)
}

/// Convert this instance to settings appropriate for a Mach-O within a universal one.
Expand All @@ -974,9 +1015,20 @@ impl<'key> SigningSettings<'key> {

// Clones this instance, promoting `main_path` to the main scope and stripping
// a prefix from other keys.
fn clone_strip_prefix(&self, main_path: &str, prefix: String) -> Self {
self.clone_with_filter_map(|_, key| match key {
SettingsScope::Main => Some(SettingsScope::Main),
fn clone_strip_prefix(
&self,
main_path: &str,
prefix: String,
preserve_settings: &[ScopedSetting],
) -> Self {
self.clone_with_filter_map(|setting, key| match key {
SettingsScope::Main => {
if preserve_settings.contains(&setting) {
Some(SettingsScope::Main)
} else {
None
}
}
SettingsScope::Path(path) => {
if path == main_path {
Some(SettingsScope::Main)
Expand All @@ -985,10 +1037,25 @@ impl<'key> SigningSettings<'key> {
.map(|path| SettingsScope::Path(path.to_string()))
}
}
SettingsScope::MultiArchIndex(index) => Some(SettingsScope::MultiArchIndex(index)),

// Top-level multiarch settings are a bit wonky: it doesn't really
// make much sense for them to propagate across binaries. But we do
// allow it.
SettingsScope::MultiArchIndex(index) => {
if preserve_settings.contains(&setting) {
Some(SettingsScope::MultiArchIndex(index))
} else {
None
}
}
SettingsScope::MultiArchCpuType(cpu_type) => {
Some(SettingsScope::MultiArchCpuType(cpu_type))
if preserve_settings.contains(&setting) {
Some(SettingsScope::MultiArchCpuType(cpu_type))
} else {
None
}
}

SettingsScope::PathMultiArchIndex(path, index) => {
if path == main_path {
Some(SettingsScope::MultiArchIndex(index))
Expand Down

0 comments on commit 8516e31

Please sign in to comment.