-
Notifications
You must be signed in to change notification settings - Fork 987
/
Copy pathsign-macos-pkg.sh
executable file
·117 lines (89 loc) · 3.34 KB
/
sign-macos-pkg.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env bash
DEV_ID="Developer ID Application: STATUS HOLDINGS PTE. LTD. (DTX7Z4U3YA)"
OBJECT="$1"
GPG_ENCRYPTED_KEYCHAIN="$2"
if [ `uname` != 'Darwin' ]; then
echo "This only works on macOS."
exit 1
elif [ $# -ne 2 ]; then
echo "sign-macos-bundle.sh <path to .app bundle or .dmg image> <path to encrypted keychain>"
exit 1
elif [ ! -e "$OBJECT" ]; then
echo "Object does not exist."
exit 1
elif [ ! -f "$GPG_ENCRYPTED_KEYCHAIN" ]; then
echo "Encrypted keychain file does not exist."
exit 1
fi
# Required env variables:
export GPG_PASS_OUTER
export GPG_PASS_INNER
export KEYCHAIN_PASS
[ -z "$GPG_PASS_OUTER" ] && echo 'Missing env var: GPG_PASS_OUTER' && exit 1
[ -z "$GPG_PASS_INNER" ] && echo 'Missing env var: GPG_PASS_INNER' && exit 1
[ -z "$KEYCHAIN_PASS" ] && echo 'Missing env var: KEYCHAIN_PASS' && exit 1
# If GPG hasn't been run on this host before, we run it once
# quietly to make sure it creates the directories it needs first
# and doesn't trip when trying to do the decryption further down
script -q /dev/null gpg < /dev/null > /dev/null
set -e
echo -e "\n### Storing original keychain search list..."
ORIG_KEYCHAIN_LIST="$(security list-keychains \
| grep -v "/Library/Keychains/System.keychain" \
| grep -v "/private/var/folders" \
| xargs)"
echo -e "\n### Creating ramdisk..."
RAMDISK="$(hdiutil attach -nomount ram://20480 | tr -d '[:blank:]')"
MOUNTPOINT="$(mktemp -d)"
KEYCHAIN="${MOUNTPOINT}/macos-developer-id.keychain-db"
function clean_up {
local STATUS=$?
set +e
if [ $STATUS -eq 0 ]; then
echo -e "\n###### DONE."
else
echo -e "\n###### ERROR. See above for details."
fi
echo -e "\n###### Cleaning up..."
echo -e "\n### Locking keychain..."
security lock-keychain "$KEYCHAIN"
echo -e "\n### Restoring original keychain search list..."
security list-keychains -s $ORIG_KEYCHAIN_LIST
security list-keychains
echo -e "\n### Delete keychain file..."
security delete-keychain "$KEYCHAIN"
echo -e "\n### Destroying ramdisk..."
diskutil umount force "$RAMDISK"
diskutil eject "$RAMDISK"
exit $STATUS
}
trap clean_up ERR EXIT
echo -e "\n### Formatting and mounting ramdisk..."
newfs_hfs "$RAMDISK"
mount -t hfs "$RAMDISK" "$MOUNTPOINT"
echo -e "\n### Decrypting keychain to $KEYCHAIN ..."
gpg --batch --passphrase "$GPG_PASS_OUTER" --pinentry-mode loopback \
--decrypt "$GPG_ENCRYPTED_KEYCHAIN" \
| gpg --batch --passphrase "$GPG_PASS_INNER" --pinentry-mode loopback \
--decrypt > "$KEYCHAIN"
echo -e "\n### Adding code-signing keychain to search list..."
security list-keychains -s $ORIG_KEYCHAIN_LIST "$KEYCHAIN"
security list-keychains
echo -e "\n### Unlocking keychain..."
security unlock-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN"
echo -e "\n### Signing object..."
# If `OBJECT` is a directory, we assume it's an app
# bundle, otherwise we consider it to be a dmg.
if [ -d "$OBJECT" ]; then
codesign --sign "$DEV_ID" --keychain "$KEYCHAIN" --deep --force --verbose=4 "$OBJECT"
else
codesign --sign "$DEV_ID" --keychain "$KEYCHAIN" --force --verbose=4 "$OBJECT"
fi
echo -e "\n### Verifying signature..."
codesign --verify --strict=all --deep --verbose=4 "$OBJECT"
echo -e "\n### Assessing Gatekeeper validation..."
if [ -d "$OBJECT" ]; then
spctl --assess --type execute --verbose=2 "$OBJECT"
else
spctl --assess --type open --context context:primary-signature --verbose=2 "$OBJECT"
fi