2 # $Id: genkey-firmengebrauch.sh 3773 2013-08-28 08:01:05Z tglase $
4 # Copyright © 2010, 2011, 2012, 2013
5 # Thorsten Glaser <t.glaser@tarent.de>
8 # Licenced under the GNU AGPLv3.
10 # Generate a new GnuPG (PGP) key, for company use.
11 # The keys are revokable by the company key and use LDAP user/password.
13 # check if we're called with mksh or bash; fix if not
14 if test -z "$shell_tried"; then
15 if test -z "$KSH_VERSION"; then
16 if mksh -c true >/dev/null 2>&1; then
21 if test -z "$BASH_VERSION"; then
22 if bash -c true >/dev/null 2>&1; then
30 if test -z "$KSH_VERSION$BASH_VERSION"; then
31 echo >&2 "I've tried but couldn't find mksh or GNU bash."
32 echo >&2 "Please call me with one of these shells."
37 # set up some basic environment
40 test -z "$BASH_VERSION" || shopt -s extglob
41 # we can now use Korn Shell extensions common to mksh and GNU bash
42 unset GPG_AGENT_INFO GPG_TTY
45 if ! tilde=$(cd && pwd) || [[ -z $tilde ]]; then
47 if ! tilde=$(cd && pwd) || [[ -z $tilde ]]; then
48 echo >&2 Eek, what\'s your home directory?
55 log="$(basename "$0").log"
58 New key generation started (Firmengebrauch)
60 ===========================================
62 test -z "$KSH_VERSION" || echo ksh >>"$log"
63 test -z "$BASH_VERSION" || echo bash >>"$log"
65 # check for existence of prerequisite tools
66 for tool in gpg wget; do
67 $tool --version >/dev/null 2>&1 && continue
68 echo >&2 You must install $tool to continue.
72 # subroutine for converting a string into an array
73 # taking into account Korn Shell vs GNU bash syntax
78 if [[ -n $KSH_VERSION ]]; then
88 # subroutines for converting array elements into hex,
89 # printing with escapes honoured/ignored
90 # taking into account Korn Shell vs GNU bash syntax
91 if [[ -n $KSH_VERSION ]]; then
92 alias arr2hex='typeset -i16 '
93 alias eprint='print -n'
94 alias nprint='print -nr -- '
100 eval _n='${#'$_vn'[*]}'
101 while (( _i < _n )); do
102 eval _v='${'$_vn'[_i]}'
103 _v=$(printf '16#%x' $_v)
104 eval $_vn'[_i++]=$_v'
115 ### BEGIN imported code {{{
117 # Thorsten Glaser <tg@mirbsd.org>
119 # Provided that these terms and disclaimer and all copyright notices
120 # are retained or reproduced in an accompanying document, permission
121 # is granted to deal in this work without restriction, including un-
122 # limited rights to use, publicly perform, distribute, sell, modify,
123 # merge, give away, or sublicence.
125 # This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
126 # the utmost extent permitted by applicable law, neither express nor
127 # implied; without malicious intent or gross negligence. In no event
128 # may a licensor, author or contributor be held liable for indirect,
129 # direct, other damage, loss, or other issues arising in any way out
130 # of dealing in the work, even if advised of the possibility of such
131 # damage or existence of a defect, except proven that it results out
132 # of said person's immediate fault when using the work as intended.
134 # read a password without echoing
145 # convert a string from UTF-8 or ISO-8859-1 to UTF-8
147 local _s="$*" _z _c _i _hv _wc _n
149 _c=$(nprint "$_s" | hexdump -ve '1/1 "16#%x "')
155 while (( _c[_i] )); do
157 if (( (_hv < 16#C2) || (_hv >= 16#F0) )); then
159 elif (( _hv < 16#E0 )); then
164 if (( _n > 1 )); then
165 (( (_c[_i + 1] & 16#C0) == 16#80 )) || _n=1
166 (( _hv == 16#E0 )) && \
167 (( _c[_i + 1] < 16#A0 )) && _n=1
169 if (( _n > 2 )); then
170 (( (_c[_i + 2] & 16#C0) == 16#80 )) || _n=1
171 (( _hv == 16#EF && _c[_i + 1] == 16#EF && \
172 _c[_i + 2] > 16#BD )) && _n=1
176 if (( (_wc = _c[_i]) < 16#80 )); then
179 (( _s[_z++] = 16#C0 | (_wc >> 6) ))
180 (( _s[_z++] = 16#80 | (_wc & 16#3F) ))
184 (( _s[_z++] = _c[_i] ))
185 (( _s[_z++] = _c[_i + 1] ))
188 (( _s[_z++] = _c[_i] ))
189 (( _s[_z++] = _c[_i + 1] ))
190 (( _s[_z++] = _c[_i + 2] ))
196 eprint "$(echo ${_s[*]} | sed -e 's/16#/\\x/g' -e 's/ //g')"
199 ### END imported code }}}
201 # create a temporary directory in /dev/shm (Linux tmpfs) or /tmp (otherwise)
202 if [[ ! -d /dev/shm/. ]] || ! T=$(mktemp -d /dev/shm/genkey.XXXXXXXXXX); then
203 if ! T=$(mktemp -d /tmp/genkey.XXXXXXXXXX); then
204 echo >&2 Cannot create temporary directory.
211 # files to overwrite before removing
212 for wipefiles in resp wgetrc; do
213 for x in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
214 echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
215 done >"$T/$wipefiles"
222 # make sure the temporary files are removed if we are interrupted
223 trap "cleanup 1" 1 2 3 13 15
227 # import company key (delete first, just in case)
228 ckid=3166EA4AF24EFF313803A739EEABC048D0620C0F
229 gpg --batch --delete-key $ckid
230 gpg --import --batch <<'EOF'
231 -----BEGIN PGP PUBLIC KEY BLOCK-----
232 Version: GnuPG v1.4.9 (MirBSD)
234 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
268 4wBQF+0/W2exE5FX3pCwrYUmYe/ItsnAZKY5RA==
270 -----END PGP PUBLIC KEY BLOCK-----
274 # gpg2, as opposed to gnupg, doesn’t want to not use the agent
275 vsn=$(gpg --version 2>&1 | head -n 1)
277 if [[ $vsn = 'gpg (GnuPG) 1.4.'* ]]; then
279 elif [[ $vsn = 'gpg (GnuPG) 1.'* ]]; then
280 echo 'WARNING: Obsolete GnuPG 1.x version, you SHALL update!'
281 elif [[ $vsn = 'gpg (GnuPG) 2.0.'* ]]; then
284 echo "WARNING: Unknown GnuPG version '$vsn', tell tglase!"
290 tarent solutions GmbH - PGP Key Generation
291 ==========================================
293 [de] Ein PGP-Schlüsselpaar wird jetzt erstellt und der öffentliche Teil
294 an den tarent-Server übertragen, sodaß die Admins diesen signieren
295 und veröffentlichen können. Außerdem wird mit diesem Schlüssel der
296 Firmenschlüssel unterschrieben; diese Signatur wird ebenfalls ver-
297 öffentlicht. Dein Name und eMail-Adresse wird aus dem LDAP bezogen
298 und das LDAP-Paßwort auch für den privaten Schlüssel verwendet.
300 [en] We will now generate a PGP keypair; the public key will be submit-
301 ted to the tarent server for being signed and published by the ad-
302 mins. The freshly generated key will also be used to sign and pub-
303 lish the company key. Your name and eMail address information will
304 be taken from the LDAP; the LDAP password will be used as password
308 # request and record user/pass
309 echo -n "LDAP login Username: "
311 [[ -n $un ]] || cleanup 0
312 askpass "LDAP login Password:"
313 [[ -n $resp ]] || cleanup 0
315 echo "login: $un" >>"$log"
317 # create wgetrc(5) to use for HTTP Basic Authentication
318 export WGETRC="$T/wgetrc"
325 cat >"$T/ca.cer" <<'EOF'
326 -----BEGIN CERTIFICATE-----
327 MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
328 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
329 BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
330 aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
331 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
332 NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
333 azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
334 YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
335 Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
336 cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
337 dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
338 WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
339 v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
340 UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
341 IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
342 W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
343 -----END CERTIFICATE-----
346 # get user information from LDAP
347 x=$(wget -O "$T/ui" --ca-certificate="$T/ca.cer" -S https://tarentpgp.tarent.de/ui.cgi 2>&1 | \
348 if md5sum --version >/dev/null 2>&1; then
349 md5sum | sed 's/ .*$//'
352 fi | sed 's/../16#& /g')
353 (echo "got user info {"; sed 's/^/ /' <"$T/ui"; echo "}") >>"$log"
355 # add entropy from CGIs to that pool (magic code ;) {{{
356 if [[ ! -s ${tilde}/.gnupg/random_seed ]]; then
357 # create and fill if it didn't exist
358 :>"${tilde}"/.gnupg/random_seed
359 chmod 0600 "${tilde}"/.gnupg/random_seed
360 dd if=/dev/urandom of="${tilde}"/.gnupg/random_seed bs=600 count=1 2>/dev/null
362 entropy=$(wget -O - -T 10 --ca-certificate="$T/ca.cer" \
363 https://call.mirbsd.org/lb.cgi?genkey.sh,1=$(hostname -f 2>/dev/null || hostname),seed=$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM 2>/dev/null | \
364 hexdump -ve '1/1 "16#%x "')$x
365 poolfile=$(hexdump -ve '1/1 "16#%x "' <"${tilde}"/.gnupg/random_seed)
368 (( n = ${#poolfile[*]} < ${#entropy[*]} ? ${#entropy[*]} : ${#poolfile[*]} ))
370 # XOR poolfile with new entropy (from CGIs)
371 while (( i < n )); do
372 (( poolfile[i % ${#poolfile[*]}] ^= entropy[i % ${#entropy[*]}] ))
375 # write back into the pool file
377 eprint "$(echo ${poolfile[*]} | sed -e 's/16#/\\x/g' -e 's/ //g')" | \
378 dd of="${tilde}"/.gnupg/random_seed conv=notrunc 2>/dev/null
379 # }}} end of magic code block ;)
381 # check the user information
386 while read key value; do
389 [[ $value = ok ]] || break
390 [[ $status = bad ]] && status=good
398 echo >&2 "Invalid server response '$key $value'"
403 if [[ $status != good || -z $i_name || -z $i_mail ]]; then
404 echo >&2 "Cannot process further (status: $status)"
405 [[ $status = bad ]] && echo >&2 Maybe wrong password.
409 # create response file for gpg
410 # NOTE: Key-Length can go up to 8192 (not more!) but please no lower
411 # than 2048 (although more than 4096 may be incompatible *AND*
413 cat >"$T/resp" <<-EOF
414 %echo Generating the key for $i_name ($i_mail) $i_comm
417 Key-Usage: auth,encrypt,sign
418 Passphrase: $(str2utf8 "$resp")
419 Name-Real: $(str2utf8 "$i_name")
420 ${i_comm:+Name-Comment: $(str2utf8 "$i_comm")}
421 Name-Email: $(str2utf8 "$i_mail")
423 Preferences: H8 H3 S8 S4 Z2 Z0 H9 H10 S9 S7
425 Keyserver: hkp://tarentpgp.tarent.de
430 # really generate the key
432 (gpg --no-use-agent --batch --gen-key "$T/resp"; echo $? >"$T/rc") 2>&1 | \
435 (echo "create key {"; sed 's/^/ /' <"$T/gen.out"; echo "}") >>"$log"
436 # check for error exit
437 if (( $(<"$T/rc") > 0 )); then
438 echo >&2 Key generation failed.
441 # scan the gpg log for keyid of keypair just created
443 's/^gpg: key \([0-9A-F]*\) marked as ultimately trusted.*$/\1/p' \
445 if [[ $pkid != +([0-9A-F]) ]] || ! gpg -K $pkid; then
446 echo >&2 '┌─────────────────────────────────────────────────────────┐'
447 echo >&2 '│ Finding the key failed. YOU CAN USE THE KEY, BUT YOU │'
448 echo >&2 '│ *MUST* CONTACT THE ADMINS with this error message. │'
449 echo >&2 '│ Kann den neuen Schlüssel nicht finden. DU KANNST DIESES │'
450 echo >&2 '│ SCHLÜSSELPAAR BENUTZEN, ABER DU *MUẞT* DIE ADMINS mit │'
451 echo >&2 '│ dieser Fehlernachricht KONTAKTIEREN. │'
452 echo >&2 '└─────────────────────────────────────────────────────────┘'
454 echo >&2 Cannot find the key just generated.
458 # apply preference settings to our newly generated key
459 if [[ $isgpg2 = 0 ]]; then
460 usepw="$nl$(str2utf8 "$resp")"
464 gpg --no-use-agent -q -u $pkid --command-fd 4 --edit-key $pkid \
465 >>"$T/edit.log" 2>&1 4<<-EOF
466 notation preferred-email-encoding@pgp.com=partitioned,pgpmime$usepw
473 $(str2utf8 "$i_name")
474 $(str2utf8 "$un")@info.tarent.de
478 setpref H8 H3 S8 S4 Z2 Z0 Z1 H9 H10 S9 S7
480 keyserver hkp://tarentpgp.tarent.de$usepw
483 echo "=> $?" >>"$T/edit.log"
485 # sign the company key with that key
486 # XXX if the key has >1 UID, there must be an extra line
488 # after the line saying "tsign"!
489 gpg --no-ask-cert-level --no-expert --no-use-agent -q -u $pkid --command-fd 4 --edit-key $ckid \
490 >>"$T/edit.log" 2>&1 4<<-EOF
500 echo "=> $?" >>"$T/edit.log"
501 sed 's/^/│/' "$T/edit.log" >>"$log"
503 if [[ $GENKEY_DONTRUN = aye ]]; then
504 echo >&2 Meh, okay. $vsn
509 # export our own public key and the signed company key into a keyring
511 gpg --export-options no-export-attributes,export-clean \
512 --export $ckid >"$T/exp.c" 2>>"$log" || rc=$?
513 gpg --export-options no-export-attributes,export-clean,export-minimal \
514 --export $pkid >"$T/exp.p" 2>>"$log" || rc=$?
516 GNUPGHOME="$T/.gnupg" gpg --no-default-keyring --primary-keyring "$T/exp.kr" \
517 --import "$T/exp.c" 2>>"$log" || rc=$?
518 GNUPGHOME="$T/.gnupg" gpg --no-default-keyring --primary-keyring "$T/exp.kr" \
519 --import "$T/exp.p" 2>>"$log" || rc=$?
522 (echo "export error $rc"; gpg -k $pkid; echo "=> $?") >>"$log"
523 echo >&2 '┌────────────────────────────────────────────────────────┐'
524 echo >&2 '│ Exporting the key failed. YOU CAN USE THE KEY, BUT YOU │'
525 echo >&2 '│ *MUST* CONTACT THE ADMINS with this error message. │'
526 echo >&2 '│ Export des Schlüssels fehlgeschlagen. DU KANNST DIESES │'
527 echo >&2 '│ SCHLÜSSELPAAR BENUTZEN, ABER DU *MUẞT* DIE ADMINS mit │'
528 echo >&2 '│ dieser Fehlernachricht KONTAKTIEREN. │'
529 echo >&2 '└────────────────────────────────────────────────────────┘'
531 gpg -k $pkid || echo gpg ERROR -k: $?
534 echo "export ok" >>"$log"
535 GNUPGHOME="$T/.gnupg" gpg --no-default-keyring --primary-keyring "$T/exp.kr" \
536 --list-sigs >>"$log" 2>&1
538 # upload the exported keyring
539 wget -O "$T/upload" \
540 --header="Content-type: application/octet-stream" \
541 --post-file="$T/exp.kr" \
542 --ca-certificate="$T/ca.cer" \
543 https://tarentpgp.tarent.de/fu.cgi >"$T/upload.log" 2>&1
544 (echo "upload keyring {"; sed 's/^/[ /' <"$T/upload.log"; \
545 sed 's/^/] /' <"$T/upload"; echo "}") >>"$log"
547 if [[ $(head -1 "$T/upload") != "upload ok" ]]; then
548 echo >&2 '┌────────────────────────────────────────────────────────┐'
549 echo >&2 '│ Uploading the key failed. YOU CAN USE THE KEY, BUT YOU │'
550 echo >&2 '│ *MUST* CONTACT THE ADMINS with this error message. │'
551 echo >&2 '│ Upload des Schlüssels fehlgeschlagen. DU KANNST DIESES │'
552 echo >&2 '│ SCHLÜSSELPAAR BENUTZEN, ABER DU *MUẞT* DIE ADMINS mit │'
553 echo >&2 '│ dieser Fehlernachricht KONTAKTIEREN. │'
554 echo >&2 '└────────────────────────────────────────────────────────┘'
557 ┌─────────────────────────────────────────┐
558 │ Key generation finished with no errors. │
559 │ Schlüsselerzeugung fehlerfrei erledigt. │
560 └─────────────────────────────────────────┘
562 ╔═════════════════════════════════════════════════════════════════════╗
563 ║ You are responsible for backing up yout PGP secret key BY YOURSELF! ║
564 ║ Du mußt SELBER für Sicherungskopiën des privaten Schlüssels sorgen! ║
565 ╚═════════════════════════════════════════════════════════════════════╝
568 (echo "finished:"; gpg -k $pkid | sed 's/^/| /'; echo) >>"$log"
570 gpg -k $pkid || echo gpg ERROR -k: $?