|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +set -e |
| 4 | + |
| 5 | +################################################################################ |
| 6 | +# Script: import-cert.sh |
| 7 | +# Description: Imports the macOS developer certificate into the system keychain. |
| 8 | +# Creates a temporary keychain, imports the P12 certificate, and |
| 9 | +# downloads the Apple root certificate for validation. This is a |
| 10 | +# one-time setup step before signing binaries. |
| 11 | +# |
| 12 | +# Usage: import-cert.sh [--macos-skip-root-certificate] |
| 13 | +# |
| 14 | +# Required Environment Variables: |
| 15 | +# MACOS_CERTIFICATE: macOS developer certificate in P12 format (base64 encoded) |
| 16 | +# MACOS_CERTIFICATE_PASSWORD: macOS certificate password |
| 17 | +# |
| 18 | +# Optional Arguments: |
| 19 | +# --macos-skip-root-certificate: Skip importing Apple Root certificate |
| 20 | +################################################################################ |
| 21 | + |
| 22 | +# Apple certificate used to validate developer certificates https://www.apple.com/certificateauthority/ |
| 23 | +readonly APPLE_ROOT_CERTIFICATE="http://certs.apple.com/devidg2.der" |
| 24 | + |
| 25 | +function print_usage { |
| 26 | + echo |
| 27 | + echo "Usage: $0 [OPTIONS]" |
| 28 | + echo |
| 29 | + echo "Required Environment Variables:" |
| 30 | + echo -e " MACOS_CERTIFICATE\t\tmacOS developer certificate in P12 format, encoded in base64." |
| 31 | + echo -e " MACOS_CERTIFICATE_PASSWORD\tmacOS certificate password" |
| 32 | + echo |
| 33 | + echo "Optional Arguments:" |
| 34 | + echo -e " --macos-skip-root-certificate\t\tSkip importing Apple Root certificate. Useful when running in already configured environment." |
| 35 | + echo -e " --help\t\t\t\tShow this help text and exit." |
| 36 | +} |
| 37 | + |
| 38 | +function main { |
| 39 | + local mac_skip_root_certificate="" |
| 40 | + |
| 41 | + while [[ $# -gt 0 ]]; do |
| 42 | + local key="$1" |
| 43 | + case "$key" in |
| 44 | + --macos-skip-root-certificate) |
| 45 | + mac_skip_root_certificate=true |
| 46 | + shift |
| 47 | + ;; |
| 48 | + --help) |
| 49 | + print_usage |
| 50 | + exit |
| 51 | + ;; |
| 52 | + -* ) |
| 53 | + echo "ERROR: Unrecognized argument: $key" |
| 54 | + print_usage |
| 55 | + exit 1 |
| 56 | + ;; |
| 57 | + * ) |
| 58 | + echo "ERROR: Unexpected positional argument: $1" |
| 59 | + print_usage |
| 60 | + exit 1 |
| 61 | + ;; |
| 62 | + esac |
| 63 | + done |
| 64 | + |
| 65 | + ensure_macos |
| 66 | + import_certificate_mac "${mac_skip_root_certificate}" |
| 67 | +} |
| 68 | + |
| 69 | +function ensure_macos { |
| 70 | + if [[ $OSTYPE != 'darwin'* ]]; then |
| 71 | + echo -e "Certificate import is supported only on macOS" |
| 72 | + exit 1 |
| 73 | + fi |
| 74 | +} |
| 75 | + |
| 76 | +function import_certificate_mac { |
| 77 | + local -r mac_skip_root_certificate="$1" |
| 78 | + assert_env_var_not_empty "MACOS_CERTIFICATE" |
| 79 | + assert_env_var_not_empty "MACOS_CERTIFICATE_PASSWORD" |
| 80 | + |
| 81 | + local mac_certificate_pwd="${MACOS_CERTIFICATE_PASSWORD}" |
| 82 | + local keystore_pw="${RANDOM}" |
| 83 | + |
| 84 | + # Create separated keychain file to store certificate and do quick cleanup of sensitive data |
| 85 | + local db_file |
| 86 | + db_file=$(mktemp "/tmp/XXXXXX-keychain") |
| 87 | + rm -rf "${db_file}" |
| 88 | + echo "Creating separated keychain for certificate" |
| 89 | + security create-keychain -p "${keystore_pw}" "${db_file}" |
| 90 | + security default-keychain -s "${db_file}" |
| 91 | + security unlock-keychain -p "${keystore_pw}" "${db_file}" |
| 92 | + echo "${MACOS_CERTIFICATE}" | base64 -d | security import /dev/stdin -f pkcs12 -k "${db_file}" -P "${mac_certificate_pwd}" -T /usr/bin/codesign |
| 93 | + if [[ "${mac_skip_root_certificate}" == "" ]]; then |
| 94 | + # Download Apple root certificate used as root for developer certificate |
| 95 | + curl -v "${APPLE_ROOT_CERTIFICATE}" --output certificate.der |
| 96 | + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain certificate.der |
| 97 | + fi |
| 98 | + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${keystore_pw}" "${db_file}" |
| 99 | + |
| 100 | + echo "Certificate imported successfully" |
| 101 | + |
| 102 | + # NOTE: Do NOT add a trap to clean up the keychain here! |
| 103 | + # The keychain must persist for sign.sh to use it. |
| 104 | + # Cleanup is handled by sign-and-verify-binaries.sh after signing is complete. |
| 105 | +} |
| 106 | + |
| 107 | +function assert_env_var_not_empty { |
| 108 | + local -r var_name="$1" |
| 109 | + local -r var_value="${!var_name}" |
| 110 | + |
| 111 | + if [[ -z "$var_value" ]]; then |
| 112 | + echo "ERROR: Required environment variable $var_name not set." |
| 113 | + exit 1 |
| 114 | + fi |
| 115 | +} |
| 116 | + |
| 117 | +main "$@" |
| 118 | + |
0 commit comments