Sign key and export for each UID

Robin Mathew Rajan mail at robinmathewrajan.com
Tue Dec 2 12:34:58 CET 2014


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Hello Tobi, :)

This shell script might help you.

(Semi)automatic GnuPG keysigning for busy people. Sign GPG keys, upload signatures to keyservers, and mail signed keys to their owner, including support for multiple private keys to sign with. All that’s left to do is verify fingerprints, type your password, and answer any questions asked by GPG.

http://mirror.roe.ch/rel/scripts/gpg/gpg-sign-keys.sh-25

It requires mktemp and an MSA like mutt or mailx.

Usage options
================

Usage:  gpg-sign-keys.sh [options...] [-u keyids] [-f keyring] [keyids...]
Options:
        -f file  Get list of keyids to sign from keyring file
        -u ids   Key(s) to sign with, multiple -u id1 -u id2 or -u 'id1 id2'
        -x ids   eXceptions - don't process these keys (multiple like -u)
        -c addr  CC all signed key emails to address
        -b addr  BCC all signed key emails to address
        -a file  Append content of file to e-mail message
        -n name  Override your name normally obtained from /etc/passwd
        -y       Assume yes on most questions (-Y for no questions asked at all)
        -I       Don't import the -f keyring into the default keyring first
        -S       Don't sign any keys - just do the sending/mailing
        -K       Don't send signed keys to your default keyserver
        -M       Don't mail signed keys to key owners
        -E       Don't encrypt mails with owners key
        -U       Don't update the trustdb after processing all keys
        -v/-h    Display version/help and exit
The script will guide you through signing all keys in the -f keyring, or just
the keys explicitly specified. All GnuPG operations are done in your default
keyring. You will be asked to confirm every mail being sent unless -y is used.
The -u, -c, -b, -e and -n options override the env vars MYKEY, CC, BCC
and OWNER respectively. For more details, read the source.


Other general info can be found at: https://www.roe.ch/GPG

Regards,
Robin Mathew Rajan
https://www.robinmathewrajan.com/


On 02-12-2014 PM 02:05, Tobias Mueller wrote:
> Hi.
> 
> I'm digging up this thread because it asked the same question I have,
> but it hasn't really been answered:
> 
> On Tue, Sep 17, 2013 at 06:23:35AM +0000, atair wrote:
>> Is there a way to achieve the same signatures from gpg command line?
>> For example
>> $ gpg -a --export <uid>
>> exports the complete key and not just the signature. However, I
>> understand the gpg-man pages in a way that it's possible to do a
>> $ gpg -u <my_keyid> --edit-key <other's_keyid>
>>> sign <other's_first_uid>
>>> sign <other's_second_uid>
>>> ...
>>> q
> 
> What are the best practises for signing another person's key (i.e. all the UIDs 
> on a key)?
> 
> And how do you follow those using gnupg?  And is there a batch mode to automate that process?
> 
> Cheers,
>   Tobi
> 
> _______________________________________________
> Gnupg-users mailing list
> Gnupg-users at gnupg.org
> http://lists.gnupg.org/mailman/listinfo/gnupg-users
> 
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQIcBAEBCgAGBQJUfaPiAAoJEJyRZAJNoXmuZ2oQAKHx7WmFHvBcANw2vrx5lIp4
c/KwLFyHyC0y3sbmh2WdWwuKo7ygFYZp9yHvs63B0PybV4rE5xAjMrMQLBEpbKg2
f+jjUotN+LzKTNyuTe5JHd/7Nz+dS/kGidMhhNNMPzt4UDhmzuW5Cob7T3YLvA2d
kp55j3zgLqTQgaOSzHwsVgtlqbq5SAXnZCecEqXp6k6ushtYRTuar7l4bGEVNI+4
BZzQtOy8fWXSWnJjDHl8MQbWEDy/GUSSbpfEXxk1y3y4myAU5KxTHagqyRHVJKJK
wMSsjRVlE2Jt8h1EZNvoulMHIZklROySc4njVv8FV9tT7m6jFdunMQ/Tb6n0sF8e
KKa+EM0VVG/84YOaYqn6ZgOtKt9rmeO7VL/E3pCSb1qDwptKagpz5tiwQFmJPukz
p/qNYZGje/PCSghzSMvfEhtIW1tSbNOfC6rB9J776+liadz8AljjVDEndCTnPvxA
C2rKSvFq604G1Za2ZbBDjRu0SA+IyUhJu9XFyrcEkCvNvMpR/lZVmffPohW+ByYU
yQot4wETT8qppTQ9t8TQFeq7rkEyoB0eOcRn7RirXG8dMDGZQUBVDJ5SSsNaj759
sIdqcJvuPxGdpgOl85BAhdlztXT1PNk7dqC8RXConLDx+u2Zyp8iT1iMg1adMToZ
8NeeFJD/eHJ9EOYUW1bQ
=07it
-----END PGP SIGNATURE-----
-------------- next part --------------
#!/usr/bin/env bash
# gpg-sign-keys.sh - (semi)automatic GnuPG keysigning for busy people
# http://www.roe.ch/GPG
#
# Copyright (C) 2003-2008, Daniel Roethlisberger <daniel at roe.ch>
# All rights reserved.
#
# Redistribution and use, with or without modification, are permitted
# provided that the following conditions are met:
# 1. Redistributions must retain the above copyright notice, this list of
#    conditions and the following disclaimer.
# 2. The name of the author may not be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Many thanks to the following contributors of patches and good ideas:
# - Tobias Sager <tsager at gmx.ch>
# - Daniel Hottinger <hotti at hotti.ch>
# - Tobias Klauser <tklauser at nuerscht.ch>
#
# $Id: gpg-sign-keys.sh 25 2008-12-14 20:07:10Z roe $
REVISION='$Id: gpg-sign-keys.sh 25 2008-12-14 20:07:10Z roe $'


##############################################################################
# requirements

# GnuPG for the actual signing, of course   - http://www.gnupg.org/
# mktemp for secure temp file handling      - http://www.mktemp.org/
# An MSA supporting the -s/-c/-b switches (see ``configuration'' below)


##############################################################################
# environment vars

# MYKEY:   Private key(s) to sign with, whitespace separated
# CC:      Mail addresses to carbon copy the signature notifications
# BCC:     Mail addresses to blind carbon copy the signature notifications
# OWNER:   Real name of person running this script, normally from /etc/passwd


##############################################################################
# configuration

# MSA: Your mail submission agent, called as follows:
# cat message | $MSA $MSA_OPTS -s "some subject" -b "$BCC" -c "$CC" $addresses
# Using any of mail, mailx or mutt should work fine, though you should make
# sure that mail sent this way will have a sensible/valid From: header.
MSA="mutt"
MSA_OPTS=""

# GnuPG
# You can use custom extra options to pass to GnuPG, eg. --use-agent for using
# gpg-agent, or options affecting the number of questions asked by GnuPG when
# signing keys.  Use GnuPG options with care: some more intrusive options may
# alter the behaviour of GnuPG too much and break the script.
GPG="gpg"
GPG_OPTS=""


##############################################################################
# TODO / known bugs and limitations

# Should be done:
# - Better support for making gpg ask less questions
# - Better support for "check first, then do all the signing", required for
#   doing any serious work with gpg-agent -- optionally feed list of uids and
#   fingerprints to ${PAGER:-more} and provide ways to yank out keys without
#   terminating the key signing process
# - Better support for gpg-agent (currently in CVS only, but should work with
#   the current 1.2.x stable series of GnuPG, which has support for talking
#   to gpg-agent -- this will make signing many keys even easier)
# - Don't send/mail keys when there was nothing to sign

# Might be done:
# - Add support for encrypting signatures, and only send them to
#   the email addresses of their respective uid.
# - Maybe add some generic form of support for plugging into a
#   challenge-response system.
# I don't think either of these are the Right Thing To Do, but this script
# could/should implement them anyway, if just for completeness.


##############################################################################
# check requirements

if [ "x`which $GPG`" = "x" ]; then
	echo "${SCRIPT}: Get and install GnuPG from http://www.gnupg.org/" >&2
	exit 1
fi

if [ "x`which mktemp`" = "x" ]; then
	echo "${SCRIPT}: Get and install mktemp from http://www.mktemp.org/" >&2
	exit 1
fi

if [ "x`which $MSA`" = "x" ]; then
	echo "${SCRIPT}: Cannot find your MSA $MSA - fix \$MSA in $SCRIPT" >&2
	exit 1
fi


##############################################################################
# check and parse options and environment

# script basename
SCRIPT=`basename $0`

# usage and version
version() {
	echo "$SCRIPT `echo $REVISION | awk '{ print $3 }'`" >&2
	echo "Copyright (C) 2003-2008, Daniel Roethlisberger <daniel at roe.ch>" >&2
	echo "Distributed under a BSD style license, see source for details." >&2
	echo "Check http://dragon.roe.ch/bitsnpieces/scripts/gpg/ for updates." >&2
	exit 1
}
usage() {
	cat >&2 <<EOF
Usage:	$SCRIPT [options...] [-u keyids] [-f keyring] [keyids...]
Options:
	-f file	 Get list of keyids to sign from keyring file
	-u ids	 Key(s) to sign with, multiple -u id1 -u id2 or -u 'id1 id2'
	-x ids	 eXceptions - don't process these keys (multiple like -u)
	-c addr	 CC all signed key emails to address
	-b addr	 BCC all signed key emails to address
	-a file	 Append the content of file to the email body
	-n name	 Override your name normally obtained from /etc/passwd
	-y	 Assume yes on most questions (-Y for no questions asked at all)
	-I	 Don't import the -f keyring into the default keyring first
	-S	 Don't sign any keys - just do the sending/mailing
	-K	 Don't send signed keys to your default keyserver
	-M	 Don't mail signed keys to key owners
	-E	 Don't encrypt mails with owners key
	-U	 Don't update the trustdb after processing all keys
	-v/-h	 Display version/help and exit
The script will guide you through signing all keys in the -f keyring, or just
the keys explicitly specified.  All GnuPG operations are done in your default
keyring.  You will be asked to confirm every mail being sent unless -y is used.
The -u, -c, -b, and -n options override the env vars MYKEY, CC, BCC, OWNER
respectively.  For more details, read the source.
EOF
	exit 1
}

# options
unset keyring mykey except noask noask2 noimport nosign nosend nomail noupdate
unset encrypt append

eval set -- `getopt f:u:x:c:b:a:n:yYISKMEUvh "$@"` || usage
for token; do
	case "$token" in
		-f)	shift; keyring="$1"; shift;;
		-u)	shift; mykey="$mykey $1"; MYKEY="$mykey"; shift;;
		-x)	shift; except="$except $1"; shift;;
		-c)	shift; CC="$1"; shift;;
		-b)	shift; BCC="$1"; shift;;
		-a)	shift; append="$1"; shift;;
		-n)	shift; OWNER="$1"; shift;;
		-y)	shift; noask=1;;
		-Y)	shift; noask=1; noask2=1;;
		-I)	shift; noimport=1;;
		-S)	shift; nosign=1;;
		-K)	shift; nosend=1;;
		-M)	shift; nomail=1;;
		-E)	shift; noencrypt=1;;
		-U)	shift; noupdate=1;;
		-h)	shift; usage;;
		-v)	shift; version;;
		--)	shift; break;;
	esac
done
ids="$@"

# clean some vars
MYKEY=`echo $MYKEY | sed -e 's/  */ /g' -e 's/^ *//g' -e 's/ *$//g' -e 's/0x//g' | tr [:lower:] [:upper:]`
except=`echo $except | sed -e 's/  */ /g' -e 's/^ *//g' -e 's/ *$//g' -e 's/0x//g' | tr [:lower:] [:upper:]`
ids=`echo $ids | sed -e 's/  */ /g' -e 's/^ *//g' -e 's/ *$//g' -e 's/0x//g' | tr [:lower:] [:upper:]`

# need MYKEY
if [ "x$MYKEY" = "x" ]; then
	echo 'You must either use -u or set $MYKEY to your private key id(s)!' >&2
	usage
fi

# need at least a keyid or keyring
if [ "x$ids$keyring" = "x" ]; then
	echo 'You must provide key id(s) to sign, or use -f on a keyring file!' >&2
	usage
fi


##############################################################################
# functions

# -opts enabled bold echo
shout() {
	echo -n ${CB}
	echo $@${CN}
}

# ask "Question" [y|n]
ask() {
	local ans opts
	[ "$2" = "y" ] && opts="[Y/n]" || opts="[y/N]"
	while true; do
		read -p "$1? $opts " ans
		[ -z "$ans" ] && ans=${2:-n}
		case "$ans" in
			y|Y|j|J) return 0 ;;
			n|N)  return 1 ;;
		esac
	done
}

# $1: id, $2: address
mail_key() {
	mail_id="$1"
	mail_address="$2"

	mykey_list=`echo $MYKEY | sed 's/ /, /g'`
	if [ `echo $MYKEY | wc -w` -eq 1 ]; then
		key_s='key'
	else
		key_s='keys'
	fi

	cat <<EOF >$tmp
Hi, this is the $SCRIPT script running on behalf of
$OWNER.

Below is your signed key $id.  Please do not forget to sign
my owner's $key_s $mykey_list as well.  If you have reasons
not to sign the $key_s, my owner would like to know about them.

EOF

	if [ "x$nosend" = "x" ]; then
		cat <<EOF >>$tmp
Additionally your signed key has been uploaded to the keyservers.

EOF
	else
		cat <<EOF >>$tmp
Your key has not been uploaded to any keyserver.  Please make
sure that you upload your key and its signatures manually.

EOF
	fi

	if [ -n "$append" -a -r "$append" ]; then
		cat "$append" >>$tmp
	fi

	$GPG --fingerprint $mail_id >>$tmp
	$GPG --armor --export $mail_id >>$tmp

	if [ -r ~/.signature ]; then
		cat <<EOF >>$tmp

-- 
EOF
		cat ~/.signature >>$tmp
	fi

	if [ "x$noencrypt" = "x" ]; then
		mv $tmp $tmp.orig
		$GPG --armor --encrypt --encrypt-to $mail_id --recipient $mail_id < $tmp.orig > $tmp 2>/dev/null
		rm $tmp.orig
	fi

	cat $tmp | $MSA $MSA_OPTS -s "Your key $mail_id signed by $mykey_list" $mailopts $mail_address
}

# clean up
cleanup() {
	rm -rf $tmpdir
}

# console interrupt (ctrl-c)
trap_int() {
	shout 'Chickening out, already?'
	cleanup
	exit 2
}

# terminate
trap_term() {
	shout 'Ouch!'
	cleanup
	exit 2
}


##############################################################################
# set up things

# GnuPG
GPG="$GPG --no-auto-check-trustdb $GPG_OPTS"

# colours: bold and normal
CB=''
CN=''

# get owner name
if [ "x$OWNER" = "x" ]; then
	owner_id=`id -un`
	OWNER=`grep "^$owner_id:" /etc/passwd | cut -f 5 -d ':' | sed 's/^\([^,]*\),.*$/\1/'`
	OWNER=${OWNER:-my owner}
fi

# set mail options
mailopts=''
if [ "x$BCC" != "x" ]; then
	MAILOPTIONS="$mailopts -b $BCC"
fi
if [ "x$CC" != "x" ]; then
	MAILOPTIONS="$mailopts -c $CC"
fi

# trap signals
trap 'trap_int' 2
trap 'trap_term' 15

# temp files
tmpdir=`mktemp -d -t gpg-sign-keys.XXXXXXXXXXXX` || exit 1
tmp="$tmpdir/mail.tmp"


##############################################################################
# process keyring, if necessary, and prune id list

# check keyring file, dearmor
if [ "x$keyring" != "x" ]; then
	keyring=`echo "$keyring" | awk '!/\// { print "./" $1 } /\// { print $1 }'`
	if [ ! -r "$keyring" ]; then
		echo "${SCRIPT}: $keyring: No such keyring." >&2
		exit 1
	fi
	keyring_ext=`echo "$keyring" | sed 's/^.*\.\([^.]*\)$/\1/'`
	if [ "x$keyring_ext" = "xasc" ]; then
		if [ "$noask" ] || \
		   ask "Automatically dearmor keyring $keyring" n; then
			shout "Dearmoring keyring $keyring to $keyring.gpg"
			$GPG --dearmor $keyring || exit 1
			keyring="$keyring.gpg"
			if [ ! -r "$keyring" ]; then
				echo "${SCRIPT}: $keyring: No such keyring.  Dearmoring failed?" >&2
				exit 1
			fi
		else
			echo "${SCRIPT}: $keyring: Keyring is ASCII armored.  Dearmor it manually." >&2
			exit 1
		fi
		unset ans
	fi
fi

if [ "x$ids" = "x" ]; then
	GPG_KEYRING="$GPG --no-default-keyring --keyring $keyring"

	ids=`$GPG_KEYRING --list-keys | sed 's/\// /g' | awk '/^pub/ { print $3 }'`

	# import keys to main keyring
	if [ "x$noimport" = "x" ]; then
		shout "Importing keys from $keyring into default keyring..."
		$GPG_KEYRING --export | $GPG --import
	else
		shout "Skipping import - you should make sure all keys are in your default keyring"
	fi
fi

for myid in $MYKEY $except; do
	ids=`echo $ids | sed "s/ *$myid */ /g"`
done
ids=`echo $ids | sed -e 's/  */ /g' -e 's/^ *//g' -e 's/ *$//g'`


##############################################################################
# main loop

if [ `echo $ids | wc -w` -lt 1 ]; then
	shout 'No keys to sign!'
	cleanup
	exit 0
fi

# give last chance to chicken out
echo "This script's owner:  $OWNER"
echo "Your private key(s):  $MYKEY"
echo "List of keys to sign: $ids"
if [ "x$noask" = "x" ]; then
	shout "Press enter to proceed or Ctrl-C to abort..."
	read p
fi

# check for missing ids in local keyring
unset import_ids
for id in $ids; do
	if ! $GPG --fingerprint $id > /dev/null 2>&1; then
		import_ids="$import_ids $id"
	fi
done

if [ "x$import_ids" != "x" ]; then
	echo "Could not find the following ids in the local keyring:"
	echo "$import_ids"
	if ask "Import missing ids now" y; then
		$GPG --recv-keys $import_ids
	fi
fi

# process all keys
for id in $ids; do
	shout "Now processing key: $id"

	# signing
	if [ "x$nosign" = "x" ]; then
		for myid in $MYKEY; do
			shout "Using your key: $myid"
			$GPG -u $myid --sign-key $id
		done
	else
		shout "Skipping signature creation"
	fi

	# sending to keyserver
	if [ "x$nosend" = "x" ]; then
		shout "Sending key $id to keyserver..."
		$GPG --send-key $id
	else
		shout "Skipping send to keyserver"
	fi

	# sending by email
	if [ "x$nomail" = "x" ]; then
		address=`$GPG --list-key $id | egrep '<.*>' | sed 's/^.*<\(.*\)>.*$/\1/g' | head -1`
		if [ "x$address" = "x" ]; then
			shout "No email address for key $id:"
			$GPG --list-key $id
			if [ "x$noask2" = "x" ]; then
				shout -n "Enter email address for key $id: "
				read address
			fi
		fi
		if [ "x$address" != "x" ]; then
			if [ "$noask" ] || \
			   ask "Send key $id to $address" n; then
				shout "Sending key $id to $address"
				mail_key $id $address
			else
				shout "No email sent to owner of key $id"
			fi
		else
			shout "Will not send email to owner of key $id - no address given"
		fi
	else
		shout "Skipping mail"
	fi
done

# clean up and update trustdb
cleanup
if [ "x$noupdate" = "x" ]; then
	shout "Updating trustdb - this could take a while..."
	gpg --update
else
	shout "Skipping trustdb update - you should run gpg --update-trustdb manually."
fi
shout "Done."



More information about the Gnupg-users mailing list