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

Implement deep signing for macOS Notarization #924

Merged
merged 1 commit into from
Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## Omnibus 7.0:

### Deep Signing and Hardened Runtime

When packaging using the pkg packager omnibus will now deep sign all binaries and libraries in the package based of each software definition's bin_dirs and lib_dirs. When siging binaries the hardened runtime is enabled.

## Omnibus 6.0:

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.1.21
7.0.0
124 changes: 121 additions & 3 deletions lib/omnibus/packagers/pkg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class Packager::PKG < Packager::Base
build do
write_scripts

sign_software_libs_and_bins

build_component_pkg

write_distribution_file
Expand Down Expand Up @@ -177,6 +179,67 @@ def write_scripts
end
end

def sign_software_libs_and_bins
if signing_identity
log.info(log_key) { "Finding libraries and binaries that require signing." }

bin_dirs = Set[]
lib_dirs = Set[]
binaries = Set[]
libraries = Set[]

# Capture lib_dirs and bin_dirs from each software
project.softwares.each do |software|
lib_dirs.merge(software.lib_dirs)
bin_dirs.merge(software.bin_dirs)
end

# Find all binaries in each bind_dir
bin_dirs.each do |dir|
binaries.merge Dir["#{dir}/*"]
end
# Filter out symlinks, non-files, and non-executables
log.debug(log_key) { " Filtering non-binary files:" }
binaries.select! { |bin| is_binary?(bin) }

# Use otool to find all libries that are used by our binaries
binaries.each do |bin|
libraries.merge find_linked_libs bin
end

# Find all libraries in each lib_dir and add any we missed with otool
lib_dirs.each do |dir|
libraries.merge Dir["#{dir}/*"]
end

# Filter Mach-O libraries and bundles
log.debug(log_key) { " Filtering non-library files:" }
libraries.select! { |lib| is_macho?(lib) }

# Use otool to find all libries that are used by our libraries
otool_libs = Set[]
libraries.each do |lib|
otool_libs.merge find_linked_libs lib
end

# Filter Mach-O libraries and bundles
otool_libs.select! { |lib| is_macho?(lib) }
libraries.merge otool_libs

log.info(log_key) { " Signing libraries:" } unless libraries.empty?
libraries.each do |library|
log.debug(log_key) { " Signing: #{library}" }
sign_library(library)
end

log.info(log_key) { " Signing binaries:" } unless binaries.empty?
binaries.each do |binary|
log.debug(log_key) { " Signing: #{binary}" }
sign_binary(binary, true)
end
end
end

#
# Construct the intermediate build product. It can be installed with the
# Installer.app, but doesn't contain the data needed to customize the
Expand All @@ -185,16 +248,20 @@ def write_scripts
# @return [void]
#
def build_component_pkg
command = <<-EOH.gsub(/^ {8}/, "")
command = <<~EOH
pkgbuild \\
--identifier "#{safe_identifier}" \\
--version "#{safe_version}" \\
--scripts "#{scripts_dir}" \\
--root "#{project.install_dir}" \\
--install-location "#{project.install_dir}" \\
"#{component_pkg}"
--preserve-xattr \\
EOH

command << %Q{ --sign "#{signing_identity}" \\\n} if signing_identity
command << %Q{ "#{component_pkg}"}
command << %Q{\n}

Dir.chdir(staging_dir) do
shellout!(command)
end
Expand Down Expand Up @@ -229,7 +296,7 @@ def write_distribution_file
# @return [void]
#
def build_product_pkg
command = <<-EOH.gsub(/^ {8}/, "")
command = <<~EOH
productbuild \\
--distribution "#{staging_dir}/Distribution" \\
--resources "#{resources_dir}" \\
Expand Down Expand Up @@ -320,5 +387,56 @@ def safe_version
converted
end
end

#
# Given a file path return any linked libraries.
#
# @param [String] file_path
# The path to a file
# @return [Array<String>]
# The linked libs
#
def find_linked_libs(file_path)
# Find all libaries for each bin
command = "otool -L #{file_path}"

stdout = shellout!(command).stdout
stdout.slice!(file_path)
stdout.scan(/#{install_dir}\S*/)
end

def sign_library(lib)
sign_binary(lib)
end

def sign_binary(bin, hardened_runtime = false)
command = "codesign -s '#{signing_identity}' '#{bin}'"
command << %q{ --options=runtime} if hardened_runtime
## Force re-signing to deal with binaries that have the same sha.
command << %q{ --force}
command << %Q{\n}

shellout!(command)
end

def is_binary?(bin)
is_binary = File.file?(bin) &&
File.executable?(bin) &&
!File.symlink?(bin)
log.debug(log_key) { " removing from signing: #{bin}" } unless is_binary
is_binary
end

def is_macho?(lib)
is_macho = false
if is_binary?(lib)
command = "file #{lib}"

stdout = shellout!(command).stdout
is_macho = stdout.match?(/Mach-O.*library/) || stdout.match?(/Mach-O.*bundle/)
end
log.debug(log_key) { " removing from signing: #{lib}" } unless is_macho
is_macho
end
end
end
40 changes: 40 additions & 0 deletions lib/omnibus/software.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,46 @@ def maintainer(val = NULL)
end
expose :maintainer

#
# Sets the bin_dirs where this software installs bins.
#
# @example
# bin_dirs ['/opt/chef-workstation/bin']
#
# @param [Array<String>] val
# the bin_dirs of the software
#
# @return [Array<String>]
#
def bin_dirs(val = NULL)
if null?(val)
@bin_dirs || [windows_safe_path("#{install_dir}/bin"), windows_safe_path("#{install_dir}/embedded/bin")]
else
@bin_dirs = val
end
end
expose :bin_dirs

#
# Sets the lib_dirs where this software installs libs.
#
# @example
# lib_dirs ['/opt/chef-workstation/bin']
#
# @param [Array<String>] val
# the lib_dirs of the software
#
# @return [Array<String>]
#
def lib_dirs(val = NULL)
if null?(val)
@lib_dirs || [windows_safe_path("#{install_dir}/embedded/lib")]
else
@lib_dirs = val
end
end
expose :lib_dirs

#
# Add a software dependency to this software.
#
Expand Down
2 changes: 1 addition & 1 deletion lib/omnibus/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
#

module Omnibus
VERSION = "6.1.21".freeze
VERSION = "7.0.0".freeze
end
Loading