1#! /bin/csh -f
2#
3# Build SystemRootCertificates.keychain and SystemTrustSettings.plist from
4# all the certs in cwd/roots. Creates these two files in ./BuiltKeychains/.
5#
6set CWD=`pwd`
7set ROOT_CERT_DIR=$CWD/roots
8set DISTRUSTED_CERT_DIR=$CWD/distrusted
9set REVOKED_CERT_DIR=$CWD/revoked
10set KC_DIR=$CWD/BuiltKeychains
11
12if((! -e "$ROOT_CERT_DIR") || (! -e "$KC_DIR")) then
13   echo "You do not seem to be in a current security_certificates directory. Aborting."
14   exit(1)
15endif
16
17# this option is essential to process filenames containing a wildcard
18set nonomatch
19
20set ROOT_CERT_KC=SystemRootCertificates.keychain
21set ROOT_CERT_KC_PATH="$KC_DIR/$ROOT_CERT_KC"
22set SETTINGS_FILE=SystemTrustSettings.plist
23set SETTINGS_FILE_PATH="$KC_DIR/$SETTINGS_FILE"
24set TEMP_CERT_KC=SystemTempCertificates.keychain
25set TEMP_CERT_KC_PATH=/tmp/"$TEMP_CERT_KC"
26set SECURITY=/usr/bin/security
27
28# save keychain list so we don't add SystemRootCertificates to it
29set SAVED_KC_LIST=`$SECURITY list -d user`
30printf "Saved user keychain list:\n%s\n\n" "${SAVED_KC_LIST}"
31
32echo Creating empty $ROOT_CERT_KC...
33rm -f "$ROOT_CERT_KC_PATH" || exit(1)
34$SECURITY create-keychain -p "$ROOT_CERT_KC" "$ROOT_CERT_KC_PATH" || exit(1)
35
36echo Creating empty $SETTINGS_FILE...
37rm -f "$SETTINGS_FILE_PATH" || exit(1)
38$SECURITY add-trusted-cert -o "$SETTINGS_FILE_PATH" || exit(1)
39
40echo Adding root certs to $ROOT_CERT_KC...
41
42cd "$ROOT_CERT_DIR" || exit(1)
43
44set GOT_ERROR=NO
45
46foreach root (*)
47	echo Processing $root...
48	if (( "$root" == "AppleDEVID.cer" )) then
49		echo "  skipping intermediate $root for trust"
50		$SECURITY -q add-certificates -k "$ROOT_CERT_KC_PATH" "$root" || exit(1)
51	else
52		$SECURITY -q add-trusted-cert -i "$SETTINGS_FILE_PATH" -o "$SETTINGS_FILE_PATH" -k "$ROOT_CERT_KC_PATH" "$root" || exit(1)
53	endif
54end
55
56# After adding the trusted roots, add trust settings to explicitly distrust certs
57#
58echo Creating empty $TEMP_CERT_KC...
59rm -f "$TEMP_CERT_KC_PATH" || exit(1)
60$SECURITY create-keychain -p "$TEMP_CERT_KC" "$TEMP_CERT_KC_PATH" || exit(1)
61
62echo Explicitly distrusting certs...
63
64cd "$DISTRUSTED_CERT_DIR" || exit(1)
65
66foreach cert (*)
67	echo Processing $cert...
68	$SECURITY -q add-trusted-cert -i "$SETTINGS_FILE_PATH" -o "$SETTINGS_FILE_PATH" -k "$TEMP_CERT_KC_PATH" -r unspecified "$cert" || exit(1)
69end
70
71echo Explicitly revoking certs...
72
73cd "$REVOKED_CERT_DIR" || exit(1)
74
75foreach cert (*)
76	echo Processing $cert...
77	### these will eventually get a different trust result than distrusted certs, when we support that;
78	### one should produce a soft failure (warning) and the other a hard failure.
79	$SECURITY -q add-trusted-cert -i "$SETTINGS_FILE_PATH" -o "$SETTINGS_FILE_PATH" -k "$TEMP_CERT_KC_PATH" -r deny "$cert" || exit(1)
80end
81
82rm -f "$TEMP_CERT_KC_PATH" || exit(1)
83
84
85# Check that we successfully added every root in the "roots" directory
86#
87set EXPECTED=`ls -1 "$ROOT_CERT_DIR" | wc -l | awk '{print $1}'`
88
89set ACTUAL=`security find-certificate -a "$ROOT_CERT_KC_PATH" | grep "labl" | wc -l | awk '{print $1}'`
90#echo $ACTUAL
91
92if ("$EXPECTED" != "$ACTUAL") then
93	printf "Failed to add all roots (expected $EXPECTED -- actual $ACTUAL)\n"
94	exit(1)
95else
96	printf "SUCCESS - $ACTUAL certificates added\n"
97endif
98
99chmod 0644 "$SETTINGS_FILE_PATH" || exit(1)
100chmod 0644 "$ROOT_CERT_KC_PATH" || exit(1)
101
102# set the keychain list, using xargs to pass the saved argument list
103/bin/echo -n "${SAVED_KC_LIST}" | xargs $SECURITY list -d user -s
104
105set POST_KC_LIST=`$SECURITY list -d user`
106printf "Post-save user keychain list:\n%s\n\n" "${POST_KC_LIST}"
107
108echo "=== System Root Certificate Processing complete. ==="
109