From bef7e503b70c985c2d4386146fc5881e7ab3718e Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 19 Jan 2010 03:11:55 -0500 Subject: [PATCH] re-work monkeysphere-host diagnostics with an eye toward multiple host keys --- src/share/mh/diagnostics | 189 +++++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 87 deletions(-) diff --git a/src/share/mh/diagnostics b/src/share/mh/diagnostics index 8e83cc5..9409f1d 100644 --- a/src/share/mh/diagnostics +++ b/src/share/mh/diagnostics @@ -8,107 +8,88 @@ # Jamie McClelland # Daniel Kahn Gillmor # -# They are Copyright 2008-2009, and are all released under the GPL, +# They are Copyright 2008-2010, and are all released under the GPL, # version 3 or later. -# check on the status and validity of the key and public certificates +# check on the status and validity of the host's public certificates (and keys?) -diagnostics() { - -local seckey -local keysfound -local curdate -local warnwindow -local warndate -local create -local expire -local uid -local fingerprint -local badhostkeys -local problemsfound=0 - -if ! [ -d "$SYSDATADIR" ] ; then - echo "! no $SYSDATADIR directory found. Please create it." - exit -fi - -if ! [ -f "$HOST_KEY_FILE" ] ; then - echo "No host key OpenPGP pub file found!" - echo " - Recommendation: run 'monkeysphere-host import-key'" - exit -fi +# global vars for communicating between functions: -# load the host key fingerprint -load_fingerprint - -seckey=$(gpg_host --list-secret-keys --fingerprint --with-colons --fixed-list-mode) -keysfound=$(echo "$seckey" | grep -c ^sec:) -curdate=$(date +%s) +MHD_CURDATE=$(date +%s) # warn when anything is 2 months away from expiration -warnwindow='2 months' -warndate=$(advance_date $warnwindow +%s) - -if ! id monkeysphere >/dev/null ; then - echo "! No monkeysphere user found! Please create a monkeysphere system user with bash as its shell." - problemsfound=$(($problemsfound+1)) -fi +MHD_WARNWINDOW='2 months' +MHD_WARNDATE=$(advance_date $MHD_WARNWINDOW +%s) +MHD_PROBLEMSFOUND=0 + + +diagnose_key() { + local fpr="$1" + local certinfo + local create + local expire + local uid + local keysfound + local uiderrs + local errcount + + printf "Checking OpenPGP Certificate for key 0x%s\n" "$fpr" + + certinfo=$(get_cert_info "0x$fpr" <"$HOST_KEY_FILE") + keysfound=$(grep -c ^pub: <<<"$certinfo") + + if [ "$keysfound" -lt 1 ] ; then + printf "! Could not find key with fingerprint 0x%s\n" "$fpr" + # FIXME: recommend a way to resolve this! + MHD_PROBLEMSFOUND=$(($MHD_PROBLEMSFOUND+1)) + fi -echo "Checking host GPG key..." -if (( "$keysfound" < 1 )); then - echo "! No host key found. The monkeysphere-host data directory is corrupt?!?!" - echo " - Recommendation: purge the MHDATADIR ($MHDATADIR) and rerun 'monkeysphere-host import-key'" - problemsfound=$(($problemsfound+1)) -elif (( "$keysfound" > 1 )); then - echo "! More than one host key found?" - # FIXME: recommend a way to resolve this - problemsfound=$(($problemsfound+1)) -else - create=$(echo "$seckey" | grep ^sec: | cut -f6 -d:) - expire=$(echo "$seckey" | grep ^sec: | cut -f7 -d:) - fingerprint=$(echo "$seckey" | grep ^fpr: | head -n1 | cut -f10 -d:) + create=$(echo "$certinfo" | grep ^pub: | cut -f6 -d:) + expire=$(echo "$certinfo" | grep ^pub: | cut -f7 -d:) # check for key expiration: if [ "$expire" ]; then - if (( "$expire" < "$curdate" )); then - echo "! Host key is expired." - echo " - Recommendation: extend lifetime of key with 'monkeysphere-host set-expire'" - problemsfound=$(($problemsfound+1)) - elif (( "$expire" < "$warndate" )); then - echo "! Host key expires in less than $warnwindow:" $(advance_date $(( $expire - $curdate )) seconds +%F) - echo " - Recommendation: extend lifetime of key with 'monkeysphere-host set-expire'" - problemsfound=$(($problemsfound+1)) + if (( "$expire" < "$MHD_CURDATE" )); then + printf "! Host key 0x%s is expired.\n" "$fpr" + printf " - Recommendation: extend lifetime of key with 'monkeysphere-host set-expire 0x%s'\n" "$fpr" + MHD_PROBLEMSFOUND=$(($MHD_PROBLEMSFOUND+1)) + elif (( "$expire" < "$MHD_WARNDATE" )); then + printf "! Host key 0x%s expires in less than %s: %s\n" "$fpr" "$MHD_WARNWINDOW" $(advance_date $(( $expire - $MHD_CURDATE )) seconds +%F) + printf " - Recommendation: extend lifetime of key with 'monkeysphere-host set-expire %s'\n" "$fpr" + MHD_PROBLEMSFOUND=$(($MHD_PROBLEMSFOUND+1)) fi fi # and weirdnesses: - if [ "$create" ] && (( "$create" > "$curdate" )); then - echo "! Host key was created in the future(?!). Is your clock correct?" - echo " - Recommendation: Check clock ($(date +%F_%T)); use NTP?" - problemsfound=$(($problemsfound+1)) + if [ "$create" ] && (( "$create" > "$MHD_CURDATE" )); then + printf "! Host key 0x%s was created in the future(?!): %s. Is your clock correct?\n" "$fpr" $(date -d "1970-01-01 + $create seconds" +%F) + printf " - Recommendation: Check your clock (is it really %s?); use NTP?\n" $(date +%F_%T) + MHD_PROBLEMSFOUND=$(($MHD_PROBLEMSFOUND+1)) fi # check for UserID expiration: - echo "$seckey" | grep ^uid: | cut -d: -f6,7,10 | \ - while IFS=: read create expire uid ; do - # FIXME: should we be doing any checking on the form - # of the User ID? Should we be unmangling it somehow? - - if [ "$create" ] && (( "$create" > "$curdate" )); then - echo "! User ID '$uid' was created in the future(?!). Is your clock correct?" - echo " - Recommendation: Check clock ($(date +%F_%T)); use NTP?" - problemsfound=$(($problemsfound+1)) - fi - if [ "$expire" ] ; then - if (( "$expire" < "$curdate" )); then - echo "! User ID '$uid' is expired." + uiderrs=$(printf '%s\n' "$certinfo" | grep ^uid: | cut -d: -f6,7,10 | \ + while IFS=: read -r create expire uid ; do + uid=$(gpg_unescape <<<"$uid") + + check_service_name "$uid" + if [ "$create" ] && (( "$create" > "$MHD_CURDATE" )); then + printf "! The latest self-sig on User ID '%s' was created in the future(?!): %s.\n - Is your clock correct?\n" "$uid" $(date -d "1970-01-01 + $create seconds" +%F) + printf " - Recommendation: Check your clock (is it really %s ?); use NTP?\n" $(date +%F_%T) + fi + if [ "$expire" ] ; then + if (( "$expire" < "$MHD_CURDATE" )); then + printf "! User ID '%s' is expired.\n" "$uid" # FIXME: recommend a way to resolve this - problemsfound=$(($problemsfound+1)) - elif (( "$expire" < "$warndate" )); then - echo "! User ID '$uid' expires in less than $warnwindow:" $(advance_date $(( $expire - $curdate )) seconds +%F) + elif (( "$expire" < "$MHD_WARNDATE" )); then + printf "! User ID '%s' expires in less than %s: %s\n" "%s" "$MHD_WARNWINDOW" $(advance_date $(( $expire - $MHD_CURDATE )) seconds +%F) # FIXME: recommend a way to resolve this - problemsfound=$(($problemsfound+1)) + fi fi - fi - done + done) + errcount=$(grep -c '^!' <<<"$uiderrs") || \ + MHD_PROBLEMSFOUND=$(($MHD_PROBLEMSFOUND+ $errcount )) + printf '%s\n' "$uiderrs" + + # FIXME: verify that the host key is properly published to the # keyservers (do this with the non-privileged user) @@ -120,11 +101,45 @@ else # FIXME: propose adding a revoker to the host key if none exist (do we # have a way to do that after key generation?) -# FIXME: test (with ssh-keyscan?) that the running ssh -# daemon is actually offering the monkeysphere host key. +# FIXME: test (with ssh-keyscan?) that any running ssh daemon is +# actually offering the monkeysphere host key, if such a key is +# loaded. + +# FIXME: scan /proc/net/tcp and /proc/net/tcp6 to see what +# known-crypto ports (ssh, https, imaps?, ldaps?, etc) are in use +# locally. Propose bringing them into the monkeysphere. + +# FIXME: ensure that the key is of a reasonable size + +# FIXME: ensure that the cert has the right key usage flags + +# FIXME: ensure that the key doesn't match any known blacklist +} + +diagnostics() { + +MHD_PROBLEMSFOUND=0 + + +if ! [ -d "$SYSDATADIR" ] ; then + echo "! no $SYSDATADIR directory found. Please create it." + exit +fi +if ! [ -f "$HOST_KEY_FILE" ] ; then + echo "No host OpenPGP certificates file found!" + echo " - Recommendation: run 'monkeysphere-host import-key' with a service key" + exit fi +if ! id monkeysphere >/dev/null ; then + echo "! No monkeysphere user found! Please create a monkeysphere system user with bash as its shell." + MHD_PROBLEMSFOUND=$(($MHD_PROBLEMSFOUND+1)) +fi + +echo "Checking host OpenPGP certificates..." +multi_key diagnose_key + # FIXME: look at the ownership/privileges of the various keyrings, # directories housing them, etc (what should those values be? can # we make them as minimal as possible?) @@ -132,8 +147,8 @@ fi # report on any cruft from old monkeysphere version report_cruft -if [ "$problemsfound" -gt 0 ]; then - echo "When the above $problemsfound issue"$(if [ "$problemsfound" -eq 1 ] ; then echo " is" ; else echo "s are" ; fi)" resolved, please re-run:" +if [ "$MHD_PROBLEMSFOUND" -gt 0 ]; then + echo "When the above $MHD_PROBLEMSFOUND issue"$(if [ "$MHD_PROBLEMSFOUND" -eq 1 ] ; then echo " is" ; else echo "s are" ; fi)" resolved, please re-run:" echo " monkeysphere-host diagnostics" else echo "Everything seems to be in order!" -- 2.26.2