| #!/usr/bin/env bash |
|
|
| |
| |
| |
| |
| |
| |
|
|
| set -euo pipefail |
|
|
| usage() { |
| cat >&2 <<'EOF' |
| Usage: sign_macos_code.sh --target PATH --identity IDENTITY [options] |
|
|
| Options: |
| --deep true|false |
| --entitlements PATH |
| --identifier IDENTIFIER |
| --identity IDENTITY |
| --options FLAGS |
| --target PATH |
| --timestamp true|false|none |
| EOF |
| } |
|
|
| target="" |
| identity="" |
| options="" |
| entitlements_file="" |
| identifier="" |
| deep="false" |
| timestamp="true" |
|
|
| while [[ $# -gt 0 ]]; do |
| case "$1" in |
| --deep) |
| deep="${2:-}" |
| shift 2 |
| ;; |
| --entitlements) |
| entitlements_file="${2:-}" |
| shift 2 |
| ;; |
| --identifier) |
| identifier="${2:-}" |
| shift 2 |
| ;; |
| --identity) |
| identity="${2:-}" |
| shift 2 |
| ;; |
| --options) |
| options="${2:-}" |
| shift 2 |
| ;; |
| --target) |
| target="${2:-}" |
| shift 2 |
| ;; |
| --timestamp) |
| timestamp="${2:-}" |
| shift 2 |
| ;; |
| -h|--help) |
| usage |
| exit 0 |
| ;; |
| *) |
| echo "Unknown signing argument: $1" >&2 |
| usage |
| exit 2 |
| ;; |
| esac |
| done |
|
|
| if [[ -z "$target" ]]; then |
| echo "--target is required." >&2 |
| usage |
| exit 2 |
| fi |
|
|
| if [[ ! -e "$target" ]]; then |
| echo "Signing target does not exist: $target" >&2 |
| exit 1 |
| fi |
|
|
| case "$deep" in |
| true|false) ;; |
| *) |
| echo "--deep must be true or false, got '$deep'." >&2 |
| exit 2 |
| ;; |
| esac |
|
|
| case "$timestamp" in |
| true|false|none) ;; |
| *) |
| echo "--timestamp must be true, false, or none, got '$timestamp'." >&2 |
| exit 2 |
| ;; |
| esac |
|
|
| sign_with_codesign() { |
| if [[ -z "$identity" ]]; then |
| echo "Native codesign requires --identity." >&2 |
| exit 2 |
| fi |
|
|
| local -a args |
| args=(--force) |
|
|
| if [[ "$deep" == "true" ]]; then |
| args+=(--deep) |
| fi |
|
|
| if [[ -n "$options" ]]; then |
| args+=(--options "$options") |
| fi |
|
|
| case "$timestamp" in |
| true) |
| args+=(--timestamp) |
| ;; |
| false|none) |
| args+=(--timestamp=none) |
| ;; |
| esac |
|
|
| if [[ -n "$entitlements_file" ]]; then |
| args+=(--entitlements "$entitlements_file") |
| fi |
|
|
| if [[ -n "$identifier" ]]; then |
| args+=(--identifier "$identifier") |
| fi |
|
|
| args+=(--sign "$identity" "$target") |
| codesign "${args[@]}" |
| } |
|
|
| append_rcodesign_flags() { |
| local raw_options="$1" |
| local option="" |
|
|
| if [[ -z "$raw_options" ]]; then |
| return 0 |
| fi |
|
|
| IFS=',' read -ra split_options <<< "$raw_options" |
| for option in "${split_options[@]}"; do |
| option="${option//[[:space:]]/}" |
| [[ -z "$option" ]] && continue |
|
|
| case "$option" in |
| host|hard|kill|expires|restrict|library|runtime|linker-signed) |
| rcodesign_args+=(--code-signature-flags "$option") |
| ;; |
| *) |
| echo "Unsupported rcodesign code signature option: $option" >&2 |
| exit 2 |
| ;; |
| esac |
| done |
| } |
|
|
| rcodesign_options_require_notarization() { |
| local raw_options="$1" |
| local option="" |
|
|
| if [[ -z "$raw_options" || "$timestamp" != "true" ]]; then |
| return 1 |
| fi |
|
|
| IFS=',' read -ra split_options <<< "$raw_options" |
| for option in "${split_options[@]}"; do |
| option="${option//[[:space:]]/}" |
| if [[ "$option" == "runtime" ]]; then |
| return 0 |
| fi |
| done |
|
|
| return 1 |
| } |
|
|
| sign_with_rcodesign() { |
| : "${OAI_AKV_PKCS11_LIBRARY:?OAI_AKV_PKCS11_LIBRARY is required for AKV PKCS11 signing.}" |
| : "${OAI_AKV_SIGNING_CERTIFICATE_PEM:?OAI_AKV_SIGNING_CERTIFICATE_PEM is required for AKV PKCS11 signing.}" |
| : "${OAI_AKV_KEY_LABEL:?OAI_AKV_KEY_LABEL is required for AKV PKCS11 signing.}" |
|
|
| if ! command -v rcodesign >/dev/null 2>&1; then |
| echo "rcodesign was not found on PATH." >&2 |
| exit 1 |
| fi |
|
|
| local -a rcodesign_args |
| rcodesign_args=( |
| sign |
| --config-file /dev/null |
| --pkcs11-library "$OAI_AKV_PKCS11_LIBRARY" |
| --pkcs11-certificate-file "$OAI_AKV_SIGNING_CERTIFICATE_PEM" |
| --pkcs11-key-label "$OAI_AKV_KEY_LABEL" |
| ) |
|
|
| if [[ "$deep" == "false" ]]; then |
| rcodesign_args+=(--shallow) |
| fi |
|
|
| case "$timestamp" in |
| true) |
| ;; |
| false|none) |
| rcodesign_args+=(--timestamp-url none) |
| ;; |
| esac |
|
|
| append_rcodesign_flags "$options" |
| if rcodesign_options_require_notarization "$options"; then |
| rcodesign_args+=(--for-notarization) |
| fi |
|
|
| if [[ -n "$entitlements_file" ]]; then |
| rcodesign_args+=(--entitlements-xml-file "$entitlements_file") |
| fi |
|
|
| if [[ -n "$identifier" ]]; then |
| rcodesign_args+=(--binary-identifier "$identifier") |
| fi |
|
|
| rcodesign_args+=("$target") |
| rcodesign "${rcodesign_args[@]}" |
| } |
|
|
| case "${OAI_CODESIGN_BACKEND:-codesign}" in |
| codesign|"") |
| sign_with_codesign |
| ;; |
| akv-pkcs11) |
| sign_with_rcodesign |
| ;; |
| *) |
| echo "Unsupported OAI_CODESIGN_BACKEND: ${OAI_CODESIGN_BACKEND}" >&2 |
| exit 2 |
| ;; |
| esac |
|
|