From 88b19565bced6d9ec9b035d1f9fe51ce6567923b Mon Sep 17 00:00:00 2001 From: Jameson Graef Rollins Date: Wed, 18 Feb 2009 20:38:23 -0500 Subject: add no-tty, quiet, and no-greeting to gpg wrapper invocations to supress as much gpg output as possible. then cleanup gpg invocations. --- src/share/mh/import_key | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/share/mh/import_key') diff --git a/src/share/mh/import_key b/src/share/mh/import_key index 557bb7f..266bf05 100644 --- a/src/share/mh/import_key +++ b/src/share/mh/import_key @@ -46,7 +46,7 @@ chmod 700 "${GNUPGHOME_HOST}" log verbose "importing ssh key..." # translate ssh key to a private key PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ - | gpg_host --import 2>&1 | log debug + | gpg_host --import # load the new host fpr into the fpr variable. this is so we can # create the gpg pub key file. we have to do this from the secret key -- cgit v1.2.3 From 62374dd1c16a2719202955ad3fe878be5cc14dba Mon Sep 17 00:00:00 2001 From: Jameson Graef Rollins Date: Wed, 18 Feb 2009 20:56:14 -0500 Subject: new msmktempdir function, to simplify making temporary directories. remove MHTMPDIR, since it's not needed. --- src/monkeysphere-host | 6 +----- src/share/common | 5 +++++ src/share/m/gen_subkey | 2 +- src/share/m/import_subkey | 2 +- src/share/m/subkey_to_ssh_agent | 2 +- src/share/mh/add_revoker | 2 +- src/share/mh/import_key | 1 - src/share/mh/publish_key | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/share/mh/import_key') diff --git a/src/monkeysphere-host b/src/monkeysphere-host index 7e8dd27..a86a8c9 100755 --- a/src/monkeysphere-host +++ b/src/monkeysphere-host @@ -32,10 +32,6 @@ MHSHAREDIR="${SYSSHAREDIR}/mh" # datadir for host functions MHDATADIR="${SYSDATADIR}/host" -# temp directory for temp gnupghome directories for add_revoker -MHTMPDIR="${MHDATADIR}/tmp" -export MHTMPDIR - # host pub key files HOST_KEY_FILE="${SYSDATADIR}/ssh_host_rsa_key.pub.gpg" @@ -171,7 +167,7 @@ show_key() { local GNUPGHOME # tmp gpghome dir - export GNUPGHOME=$(mktemp -d) + export GNUPGHOME=$(msmktempdir) # trap to remove tmp dir if break trap "rm -rf $GNUPGHOME" EXIT diff --git a/src/share/common b/src/share/common index 4120259..6b7d51b 100644 --- a/src/share/common +++ b/src/share/common @@ -134,6 +134,11 @@ cutline() { head --line="$1" "$2" | tail -1 } +# make a temporary directly +msmktempdir() { + mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX +} + # this is a wrapper for doing lock functions. # # it lets us depend on either lockfile-progs (preferred) or procmail's diff --git a/src/share/m/gen_subkey b/src/share/m/gen_subkey index cbefaa3..19d384d 100644 --- a/src/share/m/gen_subkey +++ b/src/share/m/gen_subkey @@ -114,7 +114,7 @@ EOF ) log verbose "generating subkey..." - fifoDir=$(mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) + fifoDir=$(msmktempdir) (umask 077 && mkfifo "$fifoDir/pass") echo "$editCommands" | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --edit-key "$keyID" & diff --git a/src/share/m/import_subkey b/src/share/m/import_subkey index aa89958..8b04456 100644 --- a/src/share/m/import_subkey +++ b/src/share/m/import_subkey @@ -42,7 +42,7 @@ Type '$PGRM help' for usage." done log verbose "importing ssh key..." - fifoDir=$(mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) + fifoDir=$(msmktempdir) (umask 077 && mkfifo "$fifoDir/pass") ssh2openpgp | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --import & diff --git a/src/share/m/subkey_to_ssh_agent b/src/share/m/subkey_to_ssh_agent index 012c95f..a92718e 100644 --- a/src/share/m/subkey_to_ssh_agent +++ b/src/share/m/subkey_to_ssh_agent @@ -64,7 +64,7 @@ You might want to run 'gpg --gen-key'." You might want to 'monkeysphere gen-subkey'" fi - workingdir=$(mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) + workingdir=$(msmktempdir) umask 077 mkfifo "$workingdir/passphrase" keysuccess=1 diff --git a/src/share/mh/add_revoker b/src/share/mh/add_revoker index dfce4e1..bdcb749 100644 --- a/src/share/mh/add_revoker +++ b/src/share/mh/add_revoker @@ -53,7 +53,7 @@ if [ -f "$keyID" ] ; then fi else # create a temporary directory for storing the downloaded key - TMPLOC=$(mktemp -d "${MHTMPDIR}"/tmp.XXXXXXXXXX) || failure "Could not create temporary directory!" + TMPLOC=$(msmktempdir) || failure "Could not create temporary directory!" # download the key from the keyserver as the monkeysphere user su_monkeysphere_user \ diff --git a/src/share/mh/import_key b/src/share/mh/import_key index 266bf05..cca40fa 100644 --- a/src/share/mh/import_key +++ b/src/share/mh/import_key @@ -39,7 +39,6 @@ userID="ssh://${hostName}" # create host home mkdir -p "${MHDATADIR}" -mkdir -p "${MHTMPDIR}" mkdir -p "${GNUPGHOME_HOST}" chmod 700 "${GNUPGHOME_HOST}" diff --git a/src/share/mh/publish_key b/src/share/mh/publish_key index b433ad7..37b8a72 100644 --- a/src/share/mh/publish_key +++ b/src/share/mh/publish_key @@ -27,7 +27,7 @@ else fi # create a temporary gnupg directory from which to publish the key -export GNUPGHOME=$(mktemp -d) +export GNUPGHOME=$(msmktempdir) # trap to remove tmp dir if break trap "rm -rf $GNUPGHOME" EXIT -- cgit v1.2.3 From 321ff6d4c721f2f699c57874335ce792c456a19a Mon Sep 17 00:00:00 2001 From: Jameson Graef Rollins Date: Thu, 19 Feb 2009 02:50:38 -0500 Subject: fail if hostname can not be determined in import_key --- src/share/mh/import_key | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/share/mh/import_key') diff --git a/src/share/mh/import_key b/src/share/mh/import_key index cca40fa..bca7319 100644 --- a/src/share/mh/import_key +++ b/src/share/mh/import_key @@ -21,7 +21,7 @@ hostName="$1" # use the default hostname if not specified if [ -z "$hostName" ] ; then - hostName=$(hostname -f) + hostName=$(hostname -f) || failure "Could not determine hostname." # test that the domain is not obviously illegitimate domain=${foo##*.} case $domain in -- cgit v1.2.3 From c073811aa573d0e3486c39ed9514c46e0a7a077f Mon Sep 17 00:00:00 2001 From: Jameson Graef Rollins Date: Thu, 19 Feb 2009 12:29:47 -0500 Subject: modify import_key to take the key file to import as an argument. can be '-' to import from stdin. modify man page and test accordingly. --- man/man8/monkeysphere-host.8 | 13 +++++++------ src/monkeysphere-host | 16 ++++++++-------- src/share/mh/import_key | 21 ++++++++++++++++----- tests/basic | 2 +- 4 files changed, 32 insertions(+), 20 deletions(-) (limited to 'src/share/mh/import_key') diff --git a/man/man8/monkeysphere-host.8 b/man/man8/monkeysphere-host.8 index 6c97315..f33aea6 100644 --- a/man/man8/monkeysphere-host.8 +++ b/man/man8/monkeysphere-host.8 @@ -23,9 +23,10 @@ connection authentication. \fBmonkeysphere-host\fP takes various subcommands: .TP -.B import-key [NAME[:PORT]] -Import a pem-encoded ssh secret host key, from stdin. NAME[:PORT] is -used to specify the hostname (and port) used in the user ID of the new +.B import-key FILE [NAME[:PORT]] +Import a pem-encoded ssh secret host key from file FILE. If FILE +is '-', then the key will be imported from stdin. NAME[:PORT] is used +to specify the hostname (and port) used in the user ID of the new OpenPGP key. If NAME is not specified, then the system fully-qualified domain name will be used (ie. `hostname -f'). If PORT is not specified, the no port is added to the user ID, which means @@ -35,11 +36,11 @@ port 22 is assumed. `i' may be used in place of `import-key'. Output information about host's OpenPGP and SSH keys. `s' may be used in place of `show-key'. .TP -.B extend-key EXPIRE +.B extend-key [EXPIRE] Extend the validity of the OpenPGP key for the host until EXPIRE from the present. If EXPIRE is not specified, then the user will be -prompted for the extension term. Expiration is specified like GnuPG -does: +prompted for the extension term. Expiration is specified as with +GnuPG: .nf 0 = key does not expire = key expires in n days diff --git a/src/monkeysphere-host b/src/monkeysphere-host index a67715f..9d703c2 100755 --- a/src/monkeysphere-host +++ b/src/monkeysphere-host @@ -54,9 +54,9 @@ usage: $PGRM [options] [args] Monkeysphere host admin tool. subcommands: - import-key (i) [NAME[:PORT]] import existing ssh key to gpg + import-key (i) FILE [NAME[:PORT]] import existing ssh key to gpg show-key (s) output all host key information - set-expire (e) EXPIRE set host key expiration + set-expire (e) [EXPIRE] set host key expiration add-hostname (n+) NAME[:PORT] add hostname user ID to host key revoke-hostname (n-) NAME[:PORT] revoke hostname user ID add-revoker (o) FINGERPRINT add a revoker to the host key @@ -236,6 +236,12 @@ COMMAND="$1" shift case $COMMAND in + 'import-key'|'i') + check_host_key + source "${MHSHAREDIR}/import_key" + import_key "$@" + ;; + 'show-key'|'show'|'s') check_host_no_key show_key @@ -283,12 +289,6 @@ case $COMMAND in publish_key ;; - 'import-key'|'i') - check_host_key - source "${MHSHAREDIR}/import_key" - import_key "$@" - ;; - 'diagnostics'|'d') load_fingerprint source "${MHSHAREDIR}/diagnostics" diff --git a/src/share/mh/import_key b/src/share/mh/import_key index bca7319..6394ad7 100644 --- a/src/share/mh/import_key +++ b/src/share/mh/import_key @@ -13,11 +13,13 @@ import_key() { +local sshKeyFile local hostName local domain local userID -hostName="$1" +sshKeyFile="$1" +hostName="$2" # use the default hostname if not specified if [ -z "$hostName" ] ; then @@ -42,10 +44,19 @@ mkdir -p "${MHDATADIR}" mkdir -p "${GNUPGHOME_HOST}" chmod 700 "${GNUPGHOME_HOST}" -log verbose "importing ssh key..." -# translate ssh key to a private key -PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ - | gpg_host --import +# import ssh key to a private key +if [ -z "$sshKeyFile" ] ; then + failure "Must specify ssh key file to import, or specify '-' for stdin." +elif [ "$sshKeyFile" = '-' ] ; then + log verbose "importing ssh key from stdin..." + PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ + | gpg_host --import +else + log verbose "importing ssh key from file '$sshKeyFile'..." + PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ + <"$sshKeyFile" \ + | gpg_host --import +fi # load the new host fpr into the fpr variable. this is so we can # create the gpg pub key file. we have to do this from the secret key diff --git a/tests/basic b/tests/basic index dea393f..0b91531 100755 --- a/tests/basic +++ b/tests/basic @@ -185,7 +185,7 @@ EOF echo "##################################################" echo "### import host key..." ssh-keygen -b 1024 -t rsa -N '' -f "$TEMPDIR"/ssh_host_rsa_key -monkeysphere-host import-key testhost < "$TEMPDIR"/ssh_host_rsa_key +monkeysphere-host import-key "$TEMPDIR"/ssh_host_rsa_key testhost echo "##################################################" echo "### getting host key fingerprint..." -- cgit v1.2.3 From bd64869a3b68ff8a020c381371a8ab1e24a5a0e4 Mon Sep 17 00:00:00 2001 From: Jameson Graef Rollins Date: Thu, 19 Feb 2009 15:19:02 -0500 Subject: The monkeysphere {import,gen}_subkey functions were not up-to-date. did a lot of work to bring them up-to-date, and better handle argument checking. also updated man page, changelog, and tests/basic. --- man/man1/monkeysphere.1 | 41 ++++++++++++++--------- packaging/debian/changelog | 6 ++-- src/monkeysphere | 82 ++++++++++++++++++++++++++++++++++++++++++--- src/share/m/gen_subkey | 83 ++++++++-------------------------------------- src/share/m/import_subkey | 62 ++++++++++++++++++---------------- src/share/mh/import_key | 9 +++-- tests/basic | 2 +- 7 files changed, 161 insertions(+), 124 deletions(-) (limited to 'src/share/mh/import_key') diff --git a/man/man1/monkeysphere.1 b/man/man1/monkeysphere.1 index 3ed43e1..345e1d8 100644 --- a/man/man1/monkeysphere.1 +++ b/man/man1/monkeysphere.1 @@ -56,24 +56,32 @@ ID, 1 if no matching keys were found at all, and 2 if matching keys were found but none were acceptable. `a' may be used in place of `update-authorized_keys'. .TP +.B import-subkey FILE [KEYID] +Import an existing ssh RSA key as an authentication subkey for a +private key in your GnuPG keyring. KEYID is the key ID for the +primary key for which the subkey with "authentication" capability will +be imported. If no key ID is specified, but only one key exists in +the secret keyring, that key will be used. `i' may be used in place +of `import-subkey'. +.TP .B gen-subkey [KEYID] Generate an authentication subkey for a private key in your GnuPG -keyring. For the primary key with the specified key ID, generate a -subkey with "authentication" capability that can be used for -monkeysphere transactions. An expiration length can be specified with -the `-e' or `--expire' option (prompt otherwise). If no key ID is +keyring. KEYID is the key ID for the primary key for which the subkey +with "authentication" capability will be generated. If no key ID is specified, but only one key exists in the secret keyring, that key -will be used. `g' may be used in place of `gen-subkey'. +will be used. The length of the generated key can be specified with +the `--length` or `-l` option. `g' may be used in place of +`gen-subkey'. .TP .B ssh-proxycommand -an ssh proxy command that can be used -to trigger a monkeysphere update of the ssh known_hosts file for a -host that is being connected to with ssh. This works by updating the -known_hosts file for the host first, before an attempted connection to -the host is made. Once the known_hosts file has been updated, a TCP -connection to the host is made by exec'ing netcat(1). Regular ssh -communication is then done over this netcat TCP connection (see -ProxyCommand in ssh_config(5) for more info). +An ssh ProxyCommand that can be used to trigger a monkeysphere update +of the ssh known_hosts file for a host that is being connected to with +ssh. This works by updating the known_hosts file for the host first, +before an attempted connection to the host is made. Once the +known_hosts file has been updated, a TCP connection to the host is +made by exec'ing netcat(1). Regular ssh communication is then done +over this netcat TCP connection (see ProxyCommand in ssh_config(5) for +more info). This command is meant to be run as the ssh "ProxyCommand". This can either be done by specifying the proxy command on the command line: @@ -108,9 +116,10 @@ change in the future, possibly by adding a deferred check, so that hosts that go from non-monkeysphere-enabled to monkeysphere-enabled will be properly checked. -Setting the MONKEYSPHERE_CHECK_KEYSERVER -variable (to `true' or `false') will override the keyserver-checking policy -defined above. +Setting the CHECK_KEYSERVER variable in the config file or the +MONKEYSPHERE_CHECK_KEYSERVER environment variable to either `true' or +`false' will override the keyserver-checking policy defined above and +either always or never check the keyserver for host key updates. .TP .B subkey-to-ssh-agent [ssh-add arguments] diff --git a/packaging/debian/changelog b/packaging/debian/changelog index 6a9ea18..fc317d9 100644 --- a/packaging/debian/changelog +++ b/packaging/debian/changelog @@ -16,12 +16,12 @@ monkeysphere (0.23~pre-1) UNRELEASED; urgency=low functions that require it to be there. * get rid of getopts dependency * added version output option - * check that existing authentication keys are valid in gen_key - function. + * better checks on validity of existing authentication subkeys when + doing monkeysphere {import,gen}_subkey. * add transition infrastructure for major changes between releases (see transitions/README.txt) - -- Daniel Kahn Gillmor Thu, 19 Feb 2009 02:14:44 -0500 + -- Jameson Graef Rollins Thu, 19 Feb 2009 15:11:04 -0500 monkeysphere (0.22-1) unstable; urgency=low diff --git a/src/monkeysphere b/src/monkeysphere index 992ca06..4169f2a 100755 --- a/src/monkeysphere +++ b/src/monkeysphere @@ -45,12 +45,9 @@ Monkeysphere client tool. subcommands: update-known_hosts (k) [HOST]... update known_hosts file update-authorized_keys (a) update authorized_keys file - import-subkey (i) import existing ssh key as gpg subkey - --keyfile (-f) FILE key file to import - --expire (-e) EXPIRE date to expire + import-subkey (i) FILE [KEYID] import existing ssh key as gpg subkey gen-subkey (g) [KEYID] generate an authentication subkey --length (-l) BITS key length in bits (2048) - --expire (-e) EXPIRE date to expire ssh-proxycommand monkeysphere ssh ProxyCommand subkey-to-ssh-agent (s) store authentication subkey in ssh-agent version (v) show version number @@ -59,6 +56,83 @@ subcommands: EOF } +# take a secret key ID and check that only zero or one ID is provided, +# and that it corresponds to only a single secret key ID +check_gpg_sec_key_id() { + local gpgSecOut + + case "$#" in + 0) + gpgSecOut=$(gpg --quiet --fixed-list-mode --list-secret-keys --with-colons 2>/dev/null | egrep '^sec:') + ;; + 1) + gpgSecOut=$(gpg --quiet --fixed-list-mode --list-secret-keys --with-colons "$keyID" | egrep '^sec:') || failure + ;; + *) + failure "You must specify only a single primary key ID." + ;; + esac + + # check that only a single secret key was found + case $(echo "$gpgSecOut" | grep -c '^sec:') in + 0) + failure "No secret keys found. Create an OpenPGP key with the following command: + gpg --gen-key" + ;; + 1) + echo "$gpgSecOut" | cut -d: -f5 + ;; + *) + echo "Multiple primary secret keys found:" | log error + echo "$gpgSecOut" | cut -d: -f5 | log error + echo "Please specify which primary key to use." | log error + failure + ;; + esac +} + +# check that a valid authentication subkey does not already exist +check_gpg_authentication_subkey() { + local keyID + local IFS + local line + local type + local validity + local usage + + keyID="$1" + + # check that a valid authentication key does not already exist + IFS=$'\n' + for line in $(gpg --quiet --fixed-list-mode --list-keys --with-colons "$keyID") ; do + type=$(echo "$line" | cut -d: -f1) + validity=$(echo "$line" | cut -d: -f2) + usage=$(echo "$line" | cut -d: -f12) + + # look at keys only + if [ "$type" != 'pub' -a "$type" != 'sub' ] ; then + continue + fi + # check for authentication capability + if ! check_capability "$usage" 'a' ; then + continue + fi + # if authentication key is valid, prompt to continue + if [ "$validity" = 'u' ] ; then + log error "A valid authentication key already exists for primary key '$keyID'." + if [ "$PROMPT" = "true" ] ; then + read -p "Are you sure you would like to generate another one? (y/N) " OK; OK=${OK:N} + if [ "${OK/y/Y}" != 'Y' ] ; then + failure "aborting." + fi + break + else + failure "aborting." + fi + fi + done +} + ######################################################################## # MAIN ######################################################################## diff --git a/src/share/m/gen_subkey b/src/share/m/gen_subkey index d926ad5..7c3ebb7 100644 --- a/src/share/m/gen_subkey +++ b/src/share/m/gen_subkey @@ -15,10 +15,10 @@ gen_subkey(){ local keyLength - local keyExpire + local gpgSecOut local keyID - local gpgOut - local userID + local editCommands + local fifoDir # get options while true ; do @@ -27,10 +27,6 @@ gen_subkey(){ keyLength="$2" shift 2 ;; - -e|--expire) - keyExpire="$2" - shift 2 - ;; *) if [ "$(echo "$1" | cut -c 1)" = '-' ] ; then failure "Unknown option '$1'. @@ -41,67 +37,11 @@ Type '$PGRM help' for usage." esac done - case "$#" in - 0) - gpgSecOut=$(gpg --quiet --fixed-list-mode --list-secret-keys --with-colons 2>/dev/null | egrep '^sec:') - ;; - 1) - gpgSecOut=$(gpg --quiet --fixed-list-mode --list-secret-keys --with-colons "$1" | egrep '^sec:') || failure - ;; - *) - failure "You must specify only a single primary key ID." - ;; - esac - - # check that only a single secret key was found - case $(echo "$gpgSecOut" | grep -c '^sec:') in - 0) - failure "No secret keys found. Create an OpenPGP key with the following command: - gpg --gen-key" - ;; - 1) - keyID=$(echo "$gpgSecOut" | cut -d: -f5) - ;; - *) - echo "Multiple primary secret keys found:" - echo "$gpgSecOut" | cut -d: -f5 - failure "Please specify which primary key to use." - ;; - esac + # check that the keyID is unique + keyID=$(check_gpg_sec_key_id "$@") - # check that a valid authentication key does not already exist - IFS=$'\n' - for line in $(gpg --quiet --fixed-list-mode --list-keys --with-colons "$keyID") ; do - type=$(echo "$line" | cut -d: -f1) - validity=$(echo "$line" | cut -d: -f2) - usage=$(echo "$line" | cut -d: -f12) - - # look at keys only - if [ "$type" != 'pub' -a "$type" != 'sub' ] ; then - continue - fi - # check for authentication capability - if ! check_capability "$usage" 'a' ; then - continue - fi - # if authentication key is valid, prompt to continue - if [ "$validity" = 'u' ] ; then - log error "A valid authentication key already exists for primary key '$keyID'." - if [ "$PROMPT" = "true" ] ; then - read -p "Are you sure you would like to generate another one? (y/N) " OK; OK=${OK:N} - if [ "${OK/y/Y}" != 'Y' ] ; then - failure "aborting." - fi - break - else - failure "aborting." - fi - fi - done - - # set subkey defaults - # prompt about key expiration if not specified - keyExpire=$(get_gpg_expiration "$keyExpire") + # check that an authentication subkey does not already exist + check_gpg_authentication_subkey "$keyID" # generate the list of commands that will be passed to edit-key editCommands=$(cat <