svn commit: r43392 - in head: en_US.ISO8859-1/articles/committers-guide share/pgpkeys

Warren Block wblock at FreeBSD.org
Fri Dec 27 22:57:40 UTC 2013


Author: wblock
Date: Fri Dec 27 22:57:39 2013
New Revision: 43392
URL: http://svnweb.freebsd.org/changeset/doc/43392

Log:
  Add instructions on creating an OpenPGP key.  Also add a checkkey.sh
  script that can be used to test keys for minimal security requirements.
  A long list of people helped with this.  In particular, Michael Lucas
  and David Wolfskill contributed many corrections and suggestions.  I
  started the script based on the addkey.sh script, and David Wolfskill
  worked it into something usable.  After more testing, the text can
  suggest using it to check keys before committing them.
  
  Reviewed by:	accounts@, postmaster@, mwl@, sbruno@, gavin@

Added:
  head/share/pgpkeys/checkkey.sh   (contents, props changed)
Modified:
  head/en_US.ISO8859-1/articles/committers-guide/Makefile
  head/en_US.ISO8859-1/articles/committers-guide/article.xml

Modified: head/en_US.ISO8859-1/articles/committers-guide/Makefile
==============================================================================
--- head/en_US.ISO8859-1/articles/committers-guide/Makefile	Fri Dec 27 13:43:49 2013	(r43391)
+++ head/en_US.ISO8859-1/articles/committers-guide/Makefile	Fri Dec 27 22:57:39 2013	(r43392)
@@ -13,6 +13,10 @@ INSTALL_ONLY_COMPRESSED?=
 
 SRCS=	article.xml
 
+IMAGES_LIB=	callouts/1.png
+IMAGES_LIB+=	callouts/2.png
+IMAGES_LIB+=	callouts/3.png
+
 URL_RELPREFIX?=	../../../..
 DOC_PREFIX?=	${.CURDIR}/../../..
 

Modified: head/en_US.ISO8859-1/articles/committers-guide/article.xml
==============================================================================
--- head/en_US.ISO8859-1/articles/committers-guide/article.xml	Fri Dec 27 13:43:49 2013	(r43391)
+++ head/en_US.ISO8859-1/articles/committers-guide/article.xml	Fri Dec 27 22:57:39 2013	(r43392)
@@ -166,6 +166,124 @@
     </itemizedlist>
   </sect1>
 
+  <sect1 xml:id="pgpkeys">
+    <title>Open<acronym>PGP</acronym> Keys for &os;</title>
+
+    <para>Cryptographic keys conforming to the
+      Open<acronym>PGP</acronym>
+      (<emphasis>Pretty Good Privacy</emphasis>) standard are used by
+      the &os; project to authenticate committers.  Messages carrying
+      important information like public <acronym>SSH</acronym> keys
+      can be signed with the Open<acronym>PGP</acronym> key to prove
+      that they are really from the committer.  See
+      <link xlink:href="http://www.nostarch.com/pgp_ml.htm">PGP &
+	GPG: Email for the Practical Paranoid by Michael Lucas</link>
+      and <link
+	xlink:href="http://en.wikipedia.org/wiki/Pretty_Good_Privacy"></link>
+      for more information.</para>
+
+    <sect2 xml:id="pgpkeys-creating">
+      <title>Creating a Key</title>
+
+      <para>If you do not yet have an Open<acronym>PGP</acronym> key,
+	or your key does not meet &os; security requirements, here we
+	show how to generate one.</para>
+
+      <para>Install
+	<filename role="package">security/gnupg</filename>.  Enter
+	these lines in <filename>~/.gnupg/gpg.conf</filename> to set
+	minimum acceptable defaults:</para>
+
+      <programlisting>fixed-list-mode
+keyid-format 0xlong
+personal-digest-preferences SHA512 SHA384 SHA256 SHA224
+default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 BZIP2 ZLIB ZIP Uncompressed
+use-agent
+verify-options show-uid-validity
+list-options show-uid-validity
+sig-notation issuer-fpr at notations.openpgp.fifthhorseman.net=%g
+cert-digest-algo SHA512</programlisting>
+
+      <para>Generate a key:</para>
+
+      <screen>&prompt.user; <userinput>gpg --gen-key</userinput>
+gpg (GnuPG) 2.0.22; Copyright (C) 2013 Free Software Foundation, Inc.
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+
+Warning: using insecure memory!
+Please select what kind of key you want:
+   (1) RSA and RSA (default)
+   (2) DSA and Elgamal
+   (3) DSA (sign only)
+   (4) RSA (sign only)
+Your selection? <userinput>1</userinput>
+RSA keys may be between 1024 and 4096 bits long.
+What keysize do you want? (2048) <userinput>2048</userinput>  <co xml:id="co-pgp-bits"/>
+Requested keysize is 2048 bits
+Please specify how long the key should be valid.
+         0 = key does not expire
+      <n>  = key expires in n days
+      <n>w = key expires in n weeks
+      <n>m = key expires in n months
+      <n>y = key expires in n years
+Key is valid for? (0) <userinput>3y</userinput>  <co xml:id="co-pgp-expire"/>
+Key expires at Wed Nov  4 17:20:20 2015 MST
+Is this correct? (y/N) <userinput>y</userinput>
+
+GnuPG needs to construct a user ID to identify your key.
+
+Real name: <userinput><replaceable>Chucky Daemon</replaceable></userinput> <co xml:id="co-pgp-realname"/>
+Email address: <userinput><replaceable>notreal at example.com</replaceable></userinput>
+Comment:
+You selected this USER-ID:
+    "<replaceable>Chucky Daemon <notreal at example.com></replaceable>"
+
+Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? <userinput>o</userinput>
+You need a Passphrase to protect your secret key.</screen>
+
+      <calloutlist>
+	<callout arearefs="co-pgp-bits">
+	  <para>2048-bit keys with a three-year expiration provide
+	    adequate protection at present (2013-12).  <link
+	      xlink:href="http://danielpocock.com/rsa-key-sizes-2048-or-4096-bits"/> describes the situation in more detail.</para>
+	</callout>
+
+	<callout arearefs="co-pgp-expire">
+	  <para>A three year key lifespan is short enough to obsolete
+	    keys weakened by advancing computer power, but long enough
+	    to reduce key management problems.</para>
+	</callout>
+
+	<callout arearefs="co-pgp-realname">
+	  <para>Use your real name here, preferably matching that
+	    shown on government-issued <acronym>ID</acronym> to make
+	    it easier for others to verify your identity.  Text that
+	    may help others identify you can be entered in the
+	    <literal>Comment</literal> section.</para>
+	</callout>
+      </calloutlist>
+
+      <para>After the email address is entered, a passphrase is
+	requested.  Methods of creating a secure passphrase are
+	contentious.  Rather than suggest a single way, here are some
+	links to sites that describe various methods: <link
+	  xlink:href="http://world.std.com/~reinhold/diceware.html"></link>,
+	<link
+	  xlink:href="http://www.iusmentis.com/security/passphrasefaq/"></link>,
+	<link xlink:href="http://xkcd.com/936/"></link>, <link
+	  xlink:href=""></link>.</para>
+
+      <para>Protect your private key and passphrase.  If either the
+	private key or passphrase may have been compromised or
+	disclosed, immediately notify
+	<email>accounts at FreeBSD.org</email> and revoke the key.</para>
+
+      <para>Committing the new key is shown in
+	<xref linkend="commit-list"/>.</para>
+    </sect2>
+  </sect1>
+
   <sect1 xml:id="committer.types">
     <title>Commit Bit Types</title>
 
@@ -2000,7 +2118,8 @@ ControlPersist yes</screen>
       <para>If you have been given commit rights to one or more of the
 	repositories:</para>
 
-      <itemizedlist>
+      <itemizedlist xml:id="commit-list">
+	<title>Steps for New Committers</title>
 	<listitem>
 	  <para>Add your author entity to
 	    <filename>head/share/xml/authors.ent</filename>; this

Added: head/share/pgpkeys/checkkey.sh
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/share/pgpkeys/checkkey.sh	Fri Dec 27 22:57:39 2013	(r43392)
@@ -0,0 +1,261 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+#
+# This script is intended to sanity-check PGP keys used by folks with
+# @FreeBSD.org email addresses.  The checks are intended to be derived
+# from the information at
+# <https://we.riseup.net/riseuplabs+paow/openpgp-best-practices#openpgp-key-checks>
+#
+
+\unalias -a
+
+progname=${0##*/}
+
+# Print an informational message
+info() {
+	echo "$@" >&2
+}
+
+# Print a warning message
+warning() {
+	echo "WARNING: $@" >&2
+}
+
+# Print an error message and exit
+error() {
+	echo "ERROR: $@" >&2
+	exit 1
+}
+
+# Print usage message and exit
+usage() {
+	echo "usage: ${progname} [user] [keyid ...]\n" >&2
+	exit 1
+}
+
+# Look for gpg
+gpg=$(which gpg)
+if [ $? -gt 0 -o -z "${gpg}" -o ! -x "${gpg}" ] ; then
+	error "Cannot find gpg"
+fi
+
+# Set up our internal default gpg invocation options
+_gpg() {
+	${gpg} \
+	    --display-charset utf-8 \
+	    --no-greeting \
+	    --no-secmem-warning \
+	    --keyid-format long \
+	    --list-options no-show-uid-validity \
+	    "$@"
+}
+
+# Look up key by key ID
+getkeybyid() {
+	_gpg --with-colons --list-keys "$1" 2>/dev/null | awk -F: \
+	    '$5 ~ /^\([0-9A-F]{8}\)?'"$1"'$/i && $12 ~ /ESC/ { print $5 }'
+}
+
+# Look up key by email
+getkeybyemail() {
+	_gpg --with-colons --list-keys "$1" 2>/dev/null | awk -F: \
+	    '$10 ~ /<'"$1"'>/i && $12 ~ /ESC/ { print $5 }'
+}
+
+# The first command-line argument can be a user name or a key ID.
+if [ $# -gt 0 ] ; then
+	id="$1"
+	shift
+else
+	id=$(id -nu)
+	warning "No argument specified, calculating user ID"
+fi
+
+# Now let's try to figure out what kind of thing we have as an ID.
+#  We'll check for a keyid first, as it's readily distinguishable
+#  from other things, but if we see that we have one, we push it back
+#  onto the argument list for later processing (becasue we may have
+#  been given a list of keyods).
+if echo "${id}" | egrep -q '^[0-9A-F]{16}$'; then
+	id_type="keyid"
+	set -- "${id}" $@
+elif echo "${id}" | egrep -q '^[0-9A-F]{8}$'; then
+	id_type="keyid"
+	set -- "${id}" $@
+elif echo "${id}" | egrep -iq '^[a-z][-0-9a-z_]*@([-0-9a-z]+\.)[-0-9a-z]+$'; then
+	id_type="email"
+	email="${id}"
+elif echo "${id}" | egrep -iq '^[a-z][-0-9a-z_]*$'; then
+	id_type="login"
+	login="${id}"
+	email="${id}@FreeBSD.org"
+else
+	error "Cannot recognize type of ${id} (keyid, login, or email)"
+fi
+
+if [ $# -ne 0 ] ; then
+	# Verify the keys that were specified on the command line
+	for arg ; do
+		case $(expr "${arg}" : '^[0-9A-Fa-f]\{8,16\}$') in
+		8)
+			warning "${arg}: recommend using 16-digit keyid"
+			;&
+		16)
+			keyid=$(getkeybyid "${arg}")
+			if [ -n "${keyid}" ] ; then
+				keyids="${keyids} ${keyid}"
+			else
+				warning "${arg} not found"
+			fi
+			;;
+		*)
+			warning "${arg} does not appear to be a valid key ID"
+			;;
+		esac
+		shift
+	done
+else
+	# Search for keys by freebsd.org email
+	keyids=$(getkeybyemail "${email}")
+	case $(echo "${keyids}" | wc -w) in
+	0)
+		error "no keys found for ${email}"
+		;;
+	1)
+		;;
+	*)
+		warning "Multiple keys found for <${email}>; checking all."
+		warning "If this is not what you want, specify a key ID" \
+		    "on the command line."
+		;;
+	esac
+fi
+
+# :(
+if [ -z "${keyids}" ] ; then
+	error "no valid keys were found"
+fi
+
+# add a problem report to the list of problems with this key
+badkey() {
+	key_problems="        ${key_problems}$@
+"
+}
+
+exitstatus=0
+
+# Check the keys
+for key in ${keyids} ; do
+	# no problems found yet
+	key_problems=""
+
+	IFS_save="${IFS}"
+	key_info=$( ${gpg} --no-secmem-warning --export-options export-minimal --export ${key} \
+		| ${gpg} --no-secmem-warning --list-packets )
+	# primary keys should be RSA or DSA-2
+	IFS=""
+	version=$( echo $key_info | \
+		awk '$1 == "version" && $3 == "algo" {sub(",", "", $2); print $2; exit 0}' )
+	IFS="${IFS_save}"
+	if [ $version -lt 4 ]; then
+		badkey "This key is a deprecated version $version key!"
+	fi
+
+	IFS=""
+	algonum=$( echo $key_info | \
+		awk '$1 == "version" && $3 == "algo" {sub(",", "", $4); print $4; exit 0}' )
+	IFS="${IFS_save}"
+	case ${algonum} in
+		"1")	algo="RSA" ;;
+		"17")	algo="DSA" ;;
+		"18")	algo="ECC" ;;
+		"19")	algo="ECDSA" ;;
+		*)	algo="*UNKNOWN*" ;;
+	esac
+
+	IFS=""
+	bitlen=$( echo $key_info | \
+		awk -F : '$1 ~ "pkey" { gsub("[^0-9]*","", $2); print $2; exit 0}' )
+	IFS="${IFS_save}"
+	echo "key ${key}: ${algo}, ${bitlen} bits"
+	case ${algo} in
+		RSA)	;;
+		DSA)	if [ "${bitlen}" -le 1024 ]; then \
+				badkey "DSA, but not DSA-2"; \
+			fi ;;
+		*)	badkey "non-preferred algorithm"
+	esac
+
+	# self-signatures must not use MD5 or SHA1
+	IFS=""
+	sig_algonum=$( echo $key_info | \
+		awk '$1 == "digest" && $2 == "algo" {sub(",", "", $3); print $3; exit 0}' )
+	IFS="${IFS_save}"
+	case sig_algonum in
+		1) sigs="MD5";;
+		2) sigs="SHA1";;
+		3) sigs="RIPEMD160";;
+		8) sigs="SHA256";;
+		9) sigs="SHA384";;
+		10) sigs="SHA512";;
+		11) sigs="SHA224";;
+		*)
+	esac
+	for sig in ${sigs}; do
+		if [ "${sig}" = "MD5" -o "${sig}" = "SHA1" ]; then
+			badkey "self-signature ${sig}"
+		fi
+	done
+
+	# digest algo pref must include at least one member of SHA-2
+	# at a higher priority than both MD5 and SHA1
+	IFS=""
+	algopref=$( echo $key_info | \
+		awk -F : '$1 ~ "pref-hash-algos" {gsub("[^ 0-9]", "", $2); print $2; exit 0}' )
+	IFS="${IFS_save}"
+	# if 3, 2, or 1 are before 11, 10, 9, or 8, then
+	set -- ${algopref}
+	if [ $1 -lt 4 ]; then
+		badkey "algorithm prefs do not have SHA-2 higher than MD5 or SHA1"
+	fi
+
+	# primary keys should have an expiration date at least a year
+	# in the future to make them worth committing, but no more
+	# than three years in the future
+	expires=$( _gpg --list-keys ${key} | \
+		awk "/$keyid .*expires:/ {sub(\"[^-0-9]\", \"\", \$NF); print \$NF; exit 0}" )
+	if [ -z "${expires}" ]; then
+		badkey "this key does not expire"
+	else
+		expires_s=$( date -jf "%F" "+%s" "${expires}" )
+		now_s=$( date "+%s" )
+		# 86400 == # seconds in a normal day
+		expire_int_d=$(( ( ${expires_s} - ${now_s} ) / 86400 ))
+		exp_min=$(( 1 \* 365 ))		# Min expiry time is 1 year
+		exp_max=$(( 3 \* 365 + 1 ))	# Max expiry time is 3 years
+						# We add 1 day because in a 3-year
+						# period, probability of a leap day
+						# is 297/400, about 0.74250
+		if [ ${expire_int_d} -lt ${exp_min} ]; then
+			badkey "Key $key expires in less than 1 year ($expire_int_d days)"
+		fi
+		if [ ${expire_int_d} -gt ${exp_max} ]; then
+			badkey "Key $key expires in more than 3 years ($expire_int_d days)"
+		fi
+	fi
+
+	# report problems
+	if [ -z "${key_problems}" ]; then
+		echo "    key okay, ${key} meets minimal requirements" >&2
+	else
+		exitstatus=1
+		echo "    ** problems found:" >&2
+		echo "${key_problems}" >&2
+		echo "    ** key ${key} should not be used!"
+	fi
+	echo
+done
+exit ${exitstatus}


More information about the svn-doc-head mailing list