The monkeysphere {import,gen}_subkey functions were not up-to-date.
authorJameson Graef Rollins <jrollins@finestructure.net>
Thu, 19 Feb 2009 20:19:02 +0000 (15:19 -0500)
committerJameson Graef Rollins <jrollins@finestructure.net>
Thu, 19 Feb 2009 20:19:02 +0000 (15:19 -0500)
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
packaging/debian/changelog
src/monkeysphere
src/share/m/gen_subkey
src/share/m/import_subkey
src/share/mh/import_key
tests/basic

index 3ed43e1c87e394918078918d9f508f0d76af74a3..345e1d8135190c1fb87b586bbcba996ea4801d20 100644 (file)
@@ -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]
index 6a9ea18f76e4f08c7612464edaa2cc80640f6bd9..fc317d9e1b3935bcb09a3e3a4f043368ab1b7760 100644 (file)
@@ -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 <dkg@fifthhorseman.net>  Thu, 19 Feb 2009 02:14:44 -0500
+ -- Jameson Graef Rollins <jrollins@finestructure.net>  Thu, 19 Feb 2009 15:11:04 -0500
 
 monkeysphere (0.22-1) unstable; urgency=low
 
index 992ca063ab475f5a554db0c09f787941f8807c34..4169f2a541cd4e1fe18d7b87abeb97bfcc48d568 100755 (executable)
@@ -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
 ########################################################################
index d926ad551116e57e6c3e4510b9923af5e7f23618..7c3ebb7e54ddc7b0bc04850fde94c9191961364c 100644 (file)
 
 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 <<EOF
@@ -112,19 +52,24 @@ E
 A
 Q
 $keyLength
-$keyExpire
+0
 save
 EOF
 )
 
-    log verbose "generating subkey..."
+    # setup the temp fifo dir for retrieving the key password
+    log debug "creating password fifo..."
     fifoDir=$(msmktempdir)
+    trap "rm -rf $fifoDir" EXIT
     (umask 077 && mkfifo "$fifoDir/pass")
+
+    log verbose "generating subkey..."
     echo "$editCommands" | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --edit-key "$keyID" &
 
     # FIXME: this needs to fail more gracefully if the passphrase is incorrect
     passphrase_prompt  "Please enter your passphrase for $keyID: " "$fifoDir/pass"
 
+    trap - EXIT
     rm -rf "$fifoDir"
     wait
     log verbose "done."
index 8b044568848c2ab6ca22a8717e6ed2b678b1e87c..d71c2581719db705ce4dd8b44afe624b68ef569e 100644 (file)
 # import an existing ssh key as a gpg subkey
 
 import_subkey() {
-    local keyFile="~/.ssh/id_rsa"
-    local keyExpire
+    local sshKeyFile
     local keyID
-    local gpgOut
-    local userID
-
-    # get options
-    while true ; do
-       case "$1" in
-           -f|--keyfile)
-               keyFile="$2"
-               shift 2
-               ;;
-           -e|--expire)
-               keyExpire="$2"
-               shift 2
-               ;;
-           *)
-               if [ "$(echo "$1" | cut -c 1)" = '-' ] ; then
-                   failure "Unknown option '$1'.
-Type '$PGRM help' for usage."
-               fi
-               break
-               ;;
-       esac
-    done
-
-    log verbose "importing ssh key..."
+    local gpgSecOut
+    local fifoDir
+
+    sshKeyFile="$1"
+    shift
+
+    # check that key file specified
+    if [ -z "$sshKeyFile" ] ; then
+       failure "Must specify ssh key file to import, or specify '-' for stdin."
+    fi
+
+    # check that the keyID is unique
+    keyID=$(check_gpg_sec_key_id "$@")
+
+    # check that an authentication subkey does not already exist
+    check_gpg_authentication_subkey "$keyID"
+
+    # setup the temp fifo dir for retrieving the key password
+    log debug "creating password fifo..."
     fifoDir=$(msmktempdir)
+    trap "rm -rf $fifoDir" EXIT
     (umask 077 && mkfifo "$fifoDir/pass")
-    ssh2openpgp | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --import &
 
+    # import ssh key to as authentication subkey
+    if [ "$sshKeyFile" = '-' ] ; then
+       log verbose "importing ssh key from stdin..."
+       ssh2openpgp \
+           | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --import &
+    else
+       log verbose "importing ssh key from file '$sshKeyFile'..."
+       ssh2openpgp <"$sshKeyFile" \
+           | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --import &
+    fi
+
+    # get the password if needed
     passphrase_prompt  "Please enter your passphrase for $keyID: " "$fifoDir/pass"
 
+    trap - EXIT
     rm -rf "$fifoDir"
     wait
     log verbose "done."
index 6394ad734fec1e601f92d1362329ae9ba51f06ad..040b41c57140862760b9e10dcac2189bdcb44f65 100644 (file)
@@ -21,6 +21,11 @@ local userID
 sshKeyFile="$1"
 hostName="$2"
 
+# check that key file specified
+if [ -z "$sshKeyFile" ] ; then
+    failure "Must specify ssh key file to import, or specify '-' for stdin."
+fi
+
 # use the default hostname if not specified
 if [ -z "$hostName" ] ; then
     hostName=$(hostname -f) || failure "Could not determine hostname."
@@ -45,9 +50,7 @@ mkdir -p "${GNUPGHOME_HOST}"
 chmod 700 "${GNUPGHOME_HOST}"
 
 # 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
+if [ "$sshKeyFile" = '-' ] ; then
     log verbose "importing ssh key from stdin..."
     PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \
        | gpg_host --import
index 0b91531124d00e5caa4ac419615c7a132036d0a3..3d5097791196055e89ab8c85d69d068839ef7cbd 100755 (executable)
@@ -243,7 +243,7 @@ monkeysphere-authentication list-certifiers
 # generate an auth subkey for the test user that expires in 2 days
 echo "##################################################"
 echo "### generating key for testuser..."
-monkeysphere gen-subkey --expire 2
+monkeysphere gen-subkey
 
 # add server key to testuser keychain
 echo "##################################################"