.B update-known_hosts [HOST]...
Update the known_hosts file. For each specified host, gpg will be
queried for a key associated with the host URI (see HOST
-IDENTIFICATION in monkeysphere(5)), optionally querying a keyserver.
+IDENTIFICATION in
+.BR monkeysphere(5)),
+optionally querying a keyserver.
If an acceptable key is found for the host (see KEY ACCEPTABILITY in
-monkeysphere(5)), the key is added to the user's known_hosts file. If
-a key is found but is unacceptable for the host, any matching keys are
-removed from the user's known_hosts file. If no gpg key is found for
-the host, nothing is done. If no hosts are specified, all hosts
-listed in the known_hosts file will be processed. This subcommand
-will exit with a status of 0 if at least one acceptable key was found
-for a specified host, 1 if no matching keys were found at all, and 2
-if matching keys were found but none were acceptable. `k' may be used
-in place of `update-known_hosts'.
+.BR monkeysphere(5)),
+the key is added to the user's known_hosts file. If a key is found
+but is unacceptable for the host, any matching keys are removed from
+the user's known_hosts file. If no gpg key is found for the host,
+nothing is done. If no hosts are specified, all hosts listed in the
+known_hosts file will be processed. This subcommand will exit with a
+status of 0 if at least one acceptable key was found for a specified
+host, 1 if no matching keys were found at all, and 2 if matching keys
+were found but none were acceptable. `k' may be used in place of
+`update-known_hosts'.
.TP
.B update-authorized_keys
Update the authorized_keys file for the user executing the command
each user ID in the user's authorized_user_ids file, gpg will be
queried for keys associated with that user ID, optionally querying a
keyserver. If an acceptable key is found (see KEY ACCEPTABILITY in
-monkeysphere(5)), the key is added to the user's authorized_keys file.
+.BR monkeysphere (5)),
+the key is added to the user's authorized_keys file.
If a key is found but is unacceptable for the user ID, any matching
keys are removed from the user's authorized_keys file. If no gpg key
is found for the user ID, nothing is done. This subcommand will exit
specified, but only one key exists in the secret keyring, that key
will be used. `g' may be used in place of `gen-subkey'.
.TP
+.B subkey-to-ssh-agent [ssh-add arguments]
+Push all authentication-capable subkeys in your GnuPG secret keyring
+into your running ssh-agent. Additional arguments are passed through
+to
+.BR ssh-add (1).
+For example, to remove the authentication subkeys, pass an additional
+`-d' argument. To require confirmation on each use of the key, pass
+`-c'. `s' may be used in place of `subkey-to-ssh-agent'.
+.TP
.B help
Output a brief usage summary. `h' or `?' may be used in place of
`help'.
.BR monkeysphere-server (8),
.BR monkeysphere (5),
.BR ssh (1),
+.BR ssh-add (1),
.BR gpg (1)
echo "$keyExpire"
}
+passphrase_prompt() {
+ local prompt="$1"
+ local fifo="$2"
+ local PASS
+
+ if [ "$DISPLAY" ] && which "${SSH_ASKPASS:-ssh-askpass}" >/dev/null; then
+ "${SSH_ASKPASS:-ssh-askpass}" "$prompt" > "$fifo"
+ else
+ read -s -p "$prompt" PASS
+ # Uses the builtin echo, so should not put the passphrase into
+ # the process table. I think. --dkg
+ echo "$PASS" > "$fifo"
+ fi
+}
+
+test_gnu_dummy_s2k_extension() {
+
+# this block contains a demonstration private key that has had the
+# primary key stripped out using the GNU S2K extension known as
+# "gnu-dummy" (see /usr/share/doc/gnupg/DETAILS.gz). The subkey is
+# present in cleartext, however.
+
+# openpgp2ssh will be able to deal with this based on whether the
+# local copy of GnuTLS contains read_s2k support that can handle it.
+
+# read up on that here:
+
+# http://lists.gnu.org/archive/html/gnutls-devel/2008-08/msg00005.html
+
+echo "
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+
+lQCVBEO3YdABBACRqqEnucag4+vyZny2M67Pai5+5suIRRvY+Ly8Ms5MvgCi3EVV
+xT05O/+0ShiRaf+QicCOFrhbU9PZzzU+seEvkeW2UCu4dQfILkmj+HBEIltGnHr3
+G0yegHj5pnqrcezERURf2e17gGFWX91cXB9Cm721FPXczuKraphKwCA9PwARAQAB
+/gNlAkdOVQG0OURlbW9uc3RyYXRpb24gS2V5IGZvciBTMksgR05VIGV4dGVuc2lv
+biAxMDAxIC0tIGdudS1kdW1teYi8BBMBAgAmBQJDt2HQAhsDBQkB4TOABgsJCAcD
+AgQVAggDBBYCAwECHgECF4AACgkQQZUwSa4UDezTOQP/TMQXUVrWzHYZGopoPZ2+
+ZS3qddiznBHsgb7MGYg1KlTiVJSroDUBCHIUJvdQKZV9zrzrFl47D07x6hGyUPHV
+aZXvuITW8t1o5MMHkCy3pmJ2KgfDvdUxrBvLfgPMICA4c6zA0mWquee43syEW9NY
+g3q61iPlQwD1J1kX1wlimLCdAdgEQ7dh0AEEANAwa63zlQbuy1Meliy8otwiOa+a
+mH6pxxUgUNggjyjO5qx+rl25mMjvGIRX4/L1QwIBXJBVi3SgvJW1COZxZqBYqj9U
+8HVT07mWKFEDf0rZLeUE2jTm16cF9fcW4DQhW+sfYm+hi2sY3HeMuwlUBK9KHfW2
++bGeDzVZ4pqfUEudABEBAAEAA/0bemib+wxub9IyVFUp7nPobjQC83qxLSNzrGI/
+RHzgu/5CQi4tfLOnwbcQsLELfker2hYnjsLrT9PURqK4F7udrWEoZ1I1LymOtLG/
+4tNZ7Mnul3wRC2tCn7FKx8sGJwGh/3li8vZ6ALVJAyOia5TZ/buX0+QZzt6+hPKk
+7MU1WQIA4bUBjtrsqDwro94DvPj3/jBnMZbXr6WZIItLNeVDUcM8oHL807Am97K1
+ueO/f6v1sGAHG6lVPTmtekqPSTWBfwIA7CGFvEyvSALfB8NUa6jtk27NCiw0csql
+kuhCmwXGMVOiryKEfegkIahf2bAd/gnWHPrpWp7bUE20v8YoW22I4wIAhnm5Wr5Q
+Sy7EHDUxmJm5TzadFp9gq08qNzHBpXSYXXJ3JuWcL1/awUqp3tE1I6zZ0hZ38Ia6
+SdBMN88idnhDPqPoiKUEGAECAA8FAkO3YdACGyAFCQHhM4AACgkQQZUwSa4UDezm
+vQP/ZhK+2ly9oI2z7ZcNC/BJRch0/ybQ3haahII8pXXmOThpZohr/LUgoWgCZdXg
+vP6yiszNk2tIs8KphCAw7Lw/qzDC2hEORjWO4f46qk73RAgSqG/GyzI4ltWiDhqn
+vnQCFl3+QFSe4zinqykHnLwGPMXv428d/ZjkIc2ju8dRsn4=
+=CR5w
+-----END PGP PRIVATE KEY BLOCK-----
+" | openpgp2ssh 4129E89D17C1D591 >/dev/null 2>/dev/null
+
+}
+
# remove all lines with specified string from specified file
remove_line() {
local file
gen-subkey (g) [KEYID] generate an authentication subkey
--length (-l) BITS key length in bits (2048)
--expire (-e) EXPIRE date to expire
+ subkey-to-ssh-agent (s) store authentication subkey in ssh-agent
help (h,?) this help
EOF
fifoDir=$(mktemp -d)
(umask 077 && mkfifo "$fifoDir/pass")
echo "$editCommands" | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --edit-key "$keyID" &
-
- if [ "$DISPLAY" ] && which ssh-askpass >/dev/null; then
- ssh-askpass "Please enter your passphrase for $keyID: " > "$fifoDir/pass"
- else
- read -s -p "Please enter your passphrase for $keyID: " PASS
- echo "$PASS" > "$fifoDir/pass"
- fi
+
+ passphrase_prompt "Please enter your passphrase for $keyID: " "$fifoDir/pass"
+
rm -rf "$fifoDir"
wait
log "done."
}
+function subkey_to_ssh_agent() {
+ # try to add all authentication subkeys to the agent:
+
+ local authsubkeys
+ local secretkeys
+ local subkey
+ local workingdir
+ local kname
+ local sshaddresponse
+ local keysuccess
+
+ # if there's no agent running, don't bother:
+ if [ -z "$SSH_AUTH_SOCK" ] || ! which ssh-add >/dev/null ; then
+ failure "No ssh-agent available."
+ fi
+
+ # and if it looks like it's running, but we can't actually talk to
+ # it, bail out:
+ ssh-add -l >/dev/null
+ sshaddresponse="$?"
+ if [ "$sshaddresponse" = "2" ]; then
+ failure "Could not connect to ssh-agent"
+ fi
+
+ # get list of secret keys (to work around https://bugs.g10code.com/gnupg/issue945):
+ secretkeys=$(gpg --list-secret-keys --with-colons --fixed-list-mode --fingerprint | grep '^fpr:' | cut -f10 -d: | awk '{ print "0x" $1 "!" }')
+
+ if [ -z "$secretkeys" ]; then
+ failure "You have no secret keys in your keyring!
+You might want to 'gpg --gen-key'"
+ fi
+
+ authsubkeys=$(gpg --list-secret-keys --with-colons --fixed-list-mode --fingerprint --fingerprint $secretkeys | cut -f1,5,10,12 -d: | grep -A1 '^ssb:[^:]*::[^:]*a[^:]*$' | grep '^fpr::' | cut -f3 -d: | sort -u)
+
+ if [ -z "$authsubkeys" ]; then
+ failure "no authentication-capable subkeys available.
+You might want to 'monkeysphere gen-subkey'"
+ fi
+
+ if ! test_gnu_dummy_s2k_extension ; then
+ failure "Your version of GnuTLS does not seem capable of using with gpg's exported subkeys.
+You may want to consider patching or upgrading.
+
+For more details, see:
+ http://lists.gnu.org/archive/html/gnutls-devel/2008-08/msg00005.html"
+ fi
+
+ workingdir=$(mktemp -d)
+ umask 077
+ mkfifo "$workingdir/passphrase"
+ keysuccess=1
+
+ # FIXME: we're currently allowing any other options to get passed
+ # through to ssh-add. should we limit it to known ones? For
+ # example: -d or -c and/or -t <lifetime>
+
+ for subkey in $authsubkeys; do
+ # choose a label by which this key will be known in the agent:
+ # we are labelling the key by User ID instead of by
+ # fingerprint, but filtering out all / characters to make sure
+ # the filename is legit.
+
+ primaryuid=$(gpg --with-colons --list-key "0x${subkey}!" | grep '^pub:' | cut -f10 -d: | tr -d /)
+
+ kname="[monkeysphere] $primaryuid"
+
+ if [ "$1" = '-d' ]; then
+ # we're removing the subkey:
+ gpg --export "0x${subkey}!" | openpgp2ssh "$subkey" > "$workingdir/$kname"
+ (cd "$workingdir" && ssh-add -d "$kname")
+ else
+ # we're adding the subkey:
+ mkfifo "$workingdir/$kname"
+ gpg --quiet --passphrase-fd 3 3<"$workingdir/passphrase" \
+ --export-options export-reset-subkey-passwd,export-minimal,no-export-attributes \
+ --export-secret-subkeys "0x${subkey}!" | openpgp2ssh "$subkey" > "$workingdir/$kname" &
+ (cd "$workingdir" && DISPLAY=nosuchdisplay SSH_ASKPASS=/bin/false ssh-add "$@" "$kname" </dev/null )&
+
+ passphrase_prompt "Enter passphrase for key for $primaryuid: " "$workingdir/passphrase"
+ wait %2
+ fi
+ keysuccess="$?"
+
+ rm -f "$workingdir/$kname"
+ done
+
+ rm -rf "$workingdir"
+
+ # FIXME: sort out the return values: we're just returning the
+ # success or failure of the final authentication subkey in this
+ # case. What if earlier ones failed?
+ exit "$keysuccess"
+}
+
########################################################################
# MAIN
########################################################################
gen_subkey "$@"
;;
+ 'subkey-to-ssh-agent'|'s')
+ subkey_to_ssh_agent "$@"
+ ;;
+
'--help'|'help'|'-h'|'h'|'?')
usage
;;