/[pdpsoft]/nl.nikhef.pdp.tcs/nl.nikhef.pdp.tcs.tcsg4-tools/trunk/tcsg4-install-credential.sh
ViewVC logotype

Contents of /nl.nikhef.pdp.tcs/nl.nikhef.pdp.tcs.tcsg4-tools/trunk/tcsg4-install-credential.sh

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3299 - (show annotations) (download) (as text)
Fri Jul 17 09:10:31 2020 UTC (18 months ago) by davidg
File MIME type: application/x-shellscript
File size: 12867 byte(s)
Allow password changing

1 #! /bin/sh
2 #
3 # @(#)$Id$
4 # rev 2
5 #
6 # TCS G4 client certificate format management tool for POSIX systems
7 # including installation to Grid Community Toolkit (formerly Globus)
8 # user credential directory formats
9 #
10 # Requirements: sh, awk, sed, openssl, date, mktemp, ls,
11 # mkdir, rmdir, mv, basename, grep, chmod
12 #
13 # Copyright 2020 David Groep, Nikhef, Amsterdam
14 #
15 # Licensed under the Apache License, Version 2.0 (the "License");
16 # you may not use this file except in compliance with the License.
17 # You may obtain a copy of the License at
18 #
19 # http://www.apache.org/licenses/LICENSE-2.0
20 #
21 # Unless required by applicable law or agreed to in writing, software
22 # distributed under the License is distributed on an "AS IS" BASIS,
23 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 # See the License for the specific language governing permissions and
25 # limitations under the License.
26 #
27 #
28 destdir=${HOME}/.globus
29 DATE=`date +%Y%m%d-%H%M%S`
30 progname=`basename "$0"`
31 bckprefix=backup
32 makecsr=0
33 newpass=0
34 nameformat=
35 certfn=
36
37 # ############################################################################
38 # usage help and instructions
39 #
40 help() { cat <<EOF
41 Usage: tcsg4-install-credential.sh [-d destdir] [-p passfile] [-r|-R] [-f]
42 [-n name] [-b backupprefix] <PKCS12.p12>
43
44 -d destdir write result files to <destdir>
45 if <destdir> contains "globus", also make the
46 symlinks userkey.pem and usercert.pem for GCT tools
47 -p passfile file with the password to use (same for input
48 and for output PKCS#12 and private keys)
49 -r use EEC commonName as basis for new filenames
50 -R use EEC commonName and date as basis for filenames
51 -f do not make backups of existing files
52 -n name set friendly name of the credential in corrected
53 PKCS#12 (.p12) file produced. If unset, is taken
54 from the commonName of the EEC and issuance date
55 -b bckprefix prefix of the filename to use when making backups
56 --csr generate a CSR request file for future use in destdir
57
58 <PKCS12.p12> filename of the blob produced by Sectigo
59
60 Notice: do NOT import the blob from Sectigo directly into
61 anything, since it will corrupt your key chain. Always use
62 the "package-<name>.p12" file created by this script
63
64 EOF
65 return;
66 }
67
68 # ############################################################################
69 #
70 while [ $# -gt 0 ]; do
71 case "$1" in
72 -r | --rename ) nameformat="friendly"; shift 1 ;;
73 -R | --rename-with-date ) nameformat="dated"; shift 1 ;;
74 --csr ) makecsr=1; shift 1 ;;
75 -f | --force ) bckprefix=""; shift 1 ;;
76 -h | --help ) help ; exit 0 ;;
77 -b | --backupprefix ) bckprefix="$2"; shift 2 ;;
78 -n | --name ) friendlyname="$2"; shift 2 ;;
79 -d | --destination ) destdir="$2"; shift 2 ;;
80 -p | --passfile ) passfile="$2" ; shift 2 ;;
81 --newpass ) newpass=1 ; shift ;;
82 -* ) echo "Unknown option $1, exiting" >&2 ; exit 1 ;;
83 * ) break ;;
84 esac
85 done
86
87 case $# in
88 0 ) help ; exit 0 ;;
89 1 ) pkfile="$1"; break ;;
90 * ) echo "Too many arguments." >&2 ; exit 1 ;;
91 esac
92
93 # ############################################################################
94 # input validation
95 #
96 if [ ! -r "$pkfile" ]; then echo "Cannot read $pkfile" >&2; exit 1; fi
97
98 case "$pkfile" in
99 *.p12 ) credbase=`basename "$pkfile" .p12` ;;
100 *.pfx ) credbase=`basename "$pkfile" .pfx` ;;
101 * ) echo "Unlikely PKCS#12 file: $pkfile" >&2 ; exit 2 ;;
102 esac
103
104 # ############################################################################
105 # obtain password from somewhere
106 #
107 if [ -n "$passfile" ]; then
108 if [ ! -r "$passfile" ]; then
109 echo "Error: cannot read password from $passfile" >&2 ; exit 1
110 fi
111 PW=`head -1 "$passfile"`
112 else
113 while [ x"$PW" = x"" ]; do
114 echo -ne "Passphrase (existing) for your secret key: "
115 stty -echo ; read PW ; stty echo
116 echo ""
117 done
118 fi
119 if [ -z "$PW" ]; then echo "Empty password is not allowed" >&2; exit 2; fi
120
121 if [ $newpass -ne 0 ]; then
122 while [ x"$NPW" = x"" ]; do
123 echo -ne "NEW Passphrase for your secret key and PKCS#12 package: "
124 stty -echo ; read NPW ; stty echo
125 echo ""
126 done
127 else
128 NPW="$PW"
129 fi
130
131 export PW NPW
132
133 # ############################################################################
134 # extraction of Sectigo blob of crap
135 #
136 tempdir=`mktemp -d tcsg4unpack.XXXXXX`
137
138 if [ ! -d "$tempdir" ]; then
139 echo "Error creating temporary working directory here" >&2
140 exit 1
141 fi
142
143 openssl pkcs12 -nomacver -password env:PW -in "$pkfile" \
144 -passout env:NPW -out "$tempdir/crap-$credbase.pem"
145
146 if [ $? -ne 0 ]; then
147 echo "Error: cannot extract data from PKCS12 file $pkfile" >&2
148 echo " PASSPHRASE INCORRECT?" >&2
149 exit 3
150 fi
151
152 if [ ! -s "$tempdir/crap-$credbase.pem" ]; then
153 echo "Error: cannot extract data from PKCS12 file $pkfile" >&2
154 echo " resulting direct-rendered crap file not found" >&2
155 exit 4
156 fi
157
158 if [ `grep -c PRIVATE "$tempdir/crap-$credbase.pem"` -eq 0 ]; then
159 echo "Error: cannot extract data from PKCS12 file $pkfile" >&2
160 echo " resulting crap file has no key material" >&2
161 exit 4
162 fi
163
164 if [ `grep -c CERTIFICATE "$tempdir/crap-$credbase.pem"` -eq 0 ]; then
165 echo "Error: cannot extract data from PKCS12 file $pkfile" >&2
166 echo " resulting crap file has no certificate material" >&2
167 exit 4
168 fi
169
170 # extract
171 awk '
172 BEGIN { icert = 0; }
173 /^-----BEGIN ENCRYPTED PRIVATE KEY-----$/ {
174 print $0 > "'$tempdir/key-$credbase.pem'";
175 do {
176 getline ln;
177 print ln > "'$tempdir/key-$credbase.pem'";
178 } while ( ln != "-----END ENCRYPTED PRIVATE KEY-----" );
179 }
180 /^-----BEGIN CERTIFICATE-----$/ {
181 icert++;
182 print $0 > "'$tempdir/cert-'"icert"'-$credbase.pem'";
183 do {
184 getline ln;
185 print ln > "'$tempdir/cert-'"icert"'-$credbase.pem'";
186 } while ( ln != "-----END CERTIFICATE-----" );
187 }
188 ' "$tempdir/crap-$credbase.pem"
189
190 # ############################################################################
191 # generate per-certificate and key output files
192 #
193 [ -d "$destdir" ] || mkdir -p "$destdir"
194
195 havewrittenchain=0
196 for i in "$tempdir"/cert-*-"$credbase".pem
197 do
198 certcn=`openssl x509 -noout -subject -nameopt oneline,sep_comma_plus \
199 -in "$i" | \
200 sed -e 's/.*CN = \([a-zA-Z0-9\._][- a-zA-Z0-9:\._@]*\).*/\1/'`
201 issuercn=`openssl x509 -noout -issuer -nameopt oneline,sep_comma_plus \
202 -in "$i" | \
203 sed -e 's/.*CN = \([a-zA-Z0-9\._][- a-zA-Z0-9:\._@]*\).*/\1/'`
204
205 certdate=`openssl x509 -noout -text -in "$i" | \
206 awk '/ Not Before:/ { print $4,$3,$6; }'`
207 certisca=`openssl x509 -noout -text -in "$i" | \
208 awk 'BEGIN { ca=0; }
209 /CA:FALSE/ { ca=0; } /CA:TRUE/ { ca=1; }
210 END {print ca;}'`
211
212 if [ "$certcn" = "$issuercn" -o "$issuercn" = "AddTrust External CA Root" ]
213 then
214 continue
215 fi
216
217 if [ $certisca -eq 0 ]; then
218 certfn=`echo "$certcn" | sed -e 's/[^-a-zA-Z0-9_]/_/g'`
219 certfndated=`echo "$certcn issued $certdate" | \
220 sed -e 's/[^-a-zA-Z0-9_]/_/g'`
221 echo "Processing EEC certificate: $certcn"
222 friendlyname="${friendlyname:-$certcn issued $certdate}"
223 echo " (friendly name: $friendlyname)"
224 fi
225
226 if [ $certisca -eq 1 ]; then
227 echo "Processing CA certificate: $certcn"
228 if [ $havewrittenchain -eq 0 ]; then
229 if [ -f "$destdir/chain-$credbase.pem" -a -n "$bckprefix" ]; then
230 mv "$destdir/chain-$credbase.pem" \
231 "$destdir/$bckprefix.$DATE.chain-$credbase.pem"
232 fi
233 havewrittenchain=1
234 echo "" > "$destdir/chain-$credbase.pem"
235 fi
236 cat $i >> "$destdir/chain-$credbase.pem"
237 fi
238
239 if [ $certisca -eq 0 ]; then
240 if [ -n "$pkcs12eec" ]; then
241 echo "Error: there are multiple EEC certificates in the blob" >&2
242 echo " this script cannot handle this case, sorry!" >&2
243 exit 2
244 fi
245 pkcs12eec="$i"
246 if [ -f "$destdir/cert-$credbase.pem" ]; then
247 mv "$destdir/cert-$credbase.pem" "$destdir/$bckprefix.$DATE.cert-$credbase.pem"
248 fi
249 cat $i > "$destdir/cert-$credbase.pem"
250 fi
251
252 done
253
254 echo "Processing EEC secret key"
255 if [ ! -s "$tempdir/key-$credbase.pem" ]; then
256 echo "Error: cannot find secret key file which should have been there" >&2
257 echo " internal error in AWK section (P1)" >&2
258 exit 5
259 fi
260 if [ `grep -c PRIVATE "$tempdir/key-$credbase.pem"` -eq 0 ]; then
261 echo "Error: cannot find key in keyfile which should have been there" >&2
262 echo " internal error in AWK section (P2)" >&2
263 exit 5
264 fi
265
266 if [ -f "$destdir/key-$credbase.pem" -a -n "$bckprefix" ]; then
267 mv "$destdir/key-$credbase.pem" "$destdir/$bckprefix.$DATE.key-$credbase.pem"
268 fi
269 cat "$tempdir/key-$credbase.pem" > "$destdir/key-$credbase.pem"
270
271 # not all filesystems support perms, so ignore errors
272 chmod go-rwx "$destdir/key-$credbase.pem" 2>/dev/null
273 chmod go-rwx "$destdir/cert-$credbase.pem" 2>/dev/null
274
275 echo "Repackaging $friendlyname as PKCS12"
276 if [ -f "$destdir/package-$credbase.p12" -a -n "$bckprefix" ]; then
277 mv "$destdir/package-$credbase.p12" \
278 "$destdir/$bckprefix.$DATE.package-$credbase.p12"
279 fi
280 openssl pkcs12 -export \
281 -passin env:NPW -inkey "$tempdir/key-$credbase.pem" \
282 -certfile "$destdir/chain-$credbase.pem" \
283 -name "$friendlyname" -in "$pkcs12eec" \
284 -passout env:NPW -out "$destdir/package-$credbase.p12"
285
286 if [ $? -ne 0 ]; then
287 echo "Error: something went wrong creating the normalised package" >&2
288 echo " non-zero return code from openssl in PKCS12 export (X1)" >&2
289 exit 5
290 fi
291 if [ ! -s "$destdir/package-$credbase.p12" ]; then
292 echo "Error: something went wrong creating the normalised package" >&2
293 echo " internal error in PKCS12 export (X2)" >&2
294 exit 5
295 fi
296
297 # not all filesystems support perms, so ignore errors
298 chmod go-rwx "$destdir/package-$credbase.p12" 2>/dev/null
299
300 # ############################################################################
301 # cleanup intermate files and name output properly
302 #
303 rm "$tempdir"/cert-*-$credbase.pem
304 rm "$tempdir"/crap-$credbase.pem
305 rm "$tempdir"/key-$credbase.pem
306 rmdir "$tempdir"
307 if [ $? -ne 0 ]; then
308 echo "Error: cannot remove working directory $tempdir" >&2
309 echo " internal inconsistency or prior error encountered" >&2
310 fi
311
312 # rename, if so required
313 if [ -n "$nameformat" ]; then
314 if [ "$nameformat" = "friendly" ]; then
315 certfn="${certfn:-$credbase}"
316 elif [ "$nameformat" = "dated" ]; then
317 certfn="${certfndated:-$credbase}"
318 else
319 echo "Unknown filename format, error" >&2
320 exit 2
321 fi
322 mv "$destdir/cert-$credbase.pem" "$destdir/cert-$certfn.pem"
323 mv "$destdir/chain-$credbase.pem" "$destdir/chain-$certfn.pem"
324 mv "$destdir/key-$credbase.pem" "$destdir/key-$certfn.pem"
325 mv "$destdir/package-$credbase.p12" "$destdir/package-$certfn.p12"
326 else
327 certfn="$credbase"
328 fi
329
330 # make CSR for future use if requested
331 if [ "$makecsr" -ne 0 ]; then
332 echo "Generating CSR file for future use and renewal"
333 if [ -f "$destdir/request-$credbase.pem" -a -n "$bckprefix" ]; then
334 mv "$destdir/request-$credbase.pem" \
335 "$destdir/$bckprefix.$DATE.request-$credbase.pem"
336 fi
337
338 certsubject=/`openssl x509 -noout -subject -nameopt oneline,sep_comma_plus \
339 -in "$destdir/cert-$certfn.pem" | \
340 sed -e 's/^subject= *//;s/,/\//g;s/ = /=/g'`
341
342 echo " subject: $certsubject"
343
344 openssl req -new \
345 -key "$destdir/key-$certfn.pem" -passin env:NPW \
346 -subj "$certsubject" \
347 -out "$destdir/request-$certfn.pem"
348 fi
349
350 # ############################################################################
351 # inform user of result and of globus compatibility
352 #
353 echo "The following files have been created for you:"
354 echo -ne " " ; ls -l1a "$destdir/cert-$certfn.pem"
355 echo -ne " " ; ls -l1a "$destdir/chain-$certfn.pem"
356 [ -f "$destdir/request-$certfn.pem" ] && \
357 ( echo -ne " " ; ls -l1a "$destdir/request-$certfn.pem" )
358 echo -ne " " ; ls -l1a "$destdir/key-$certfn.pem"
359 echo -ne " " ; ls -l1a "$destdir/package-$certfn.p12"
360
361 # globus-ify pertinent dest directories
362 case "$destdir" in
363 *globus* )
364 echo "Making Grid Community Toolkit compatible link in $destdir"
365 if [ -f "$destdir/userkey.pem" -a -n "$bckprefix" ]; then
366 echo " backing up userkey.pem to ""$bckprefix.$DATE.userkey.pem"
367 mv "$destdir/userkey.pem" "$destdir/$bckprefix.$DATE.userkey.pem"
368 fi
369 echo " userkey.pem"
370 ln -sfnT "key-$certfn.pem" "$destdir/userkey.pem"
371 if [ -f "$destdir/usercert.pem" -a -n "$bckprefix" ]; then
372 echo " backing up usercert.pem to $bckprefix.$DATE.usercert.pem"
373 mv "$destdir/usercert.pem" "$destdir/$bckprefix.$DATE.usercert.pem"
374 fi
375 echo " usercert.pem"
376 ln -sfnT "cert-$certfn.pem" "$destdir/usercert.pem"
377 ;;
378 esac
379
380 #
381 #
382 # ############################################################################

Properties

Name Value
svn:executable *

grid.support@nikhef.nl
ViewVC Help
Powered by ViewVC 1.1.28