From d1240f67eab6dfa7e3344cd84dd8849b38ce337c Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Mon, 15 Aug 2011 22:51:58 +1000 Subject: pacman-key: rework importing distro/repo provided keyrings The current --reload option, apart from being non-clear in its naming, is very limited in that only one keyring can be provided. A distribution may want to provide multiple keyrings for various subsets of its organisation or custom repo providers may also want to provide a keyring. This patch adds a --populate option that reads keyrings from (by default) /usr/share/pacman/keyrings. A keyring is named foo.gpg, with optional foo-revoked file providing a list of revoked key ids. These files are required to be signed (detached) by a key trusted by pacman-key, in practice probably by the key that signed the package providing these files. The --populate flag either updates the pacman keyring using all keyrings in the directory or individual keyrings can be specified. Signed-off-by: Allan McRae --- doc/pacman-key.8.txt | 8 ++- scripts/Makefile.am | 1 + scripts/pacman-key.sh.in | 150 ++++++++++++++++++++++++----------------------- 3 files changed, 83 insertions(+), 76 deletions(-) diff --git a/doc/pacman-key.8.txt b/doc/pacman-key.8.txt index 9dc175cf..f61c2eca 100644 --- a/doc/pacman-key.8.txt +++ b/doc/pacman-key.8.txt @@ -80,8 +80,12 @@ Options *-r, \--receive* :: Fetch the specified keyids from the specified key server URL. -*\--reload*:: - Reloads the keys from the keyring package. +*\--populate* []:: + Reload the default keys from the (optionally provided) keyrings in + +{pkgdatadir}/keyrings+. Each keyring is provided in a file foo.gpg that + contains the keys for the foo keyring. Optionally the file foo-revoked + contains a list of revoked key IDs for that keyring. These files are + required to be signed (detached) by a trusted PGP key. *-u, \--updatedb*:: Equivalent to \--check-trustdb in GnuPG. diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 802b8f4e..52a784ab 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -44,6 +44,7 @@ edit = sed \ -e 's|@localedir[@]|$(localedir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ + -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \ -e 's|@prefix[@]|$(prefix)|g' \ -e '1s|!/bin/bash|!$(BASH_SHELL)|g' \ -e 's|@PACKAGE_VERSION[@]|$(REAL_PACKAGE_VERSION)|g' \ diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 74ecfcf1..85801006 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -37,8 +37,8 @@ IMPORT_TRUSTDB=0 INIT=0 LISTKEYS=0 LISTSIGS=0 +POPULATE=0 RECEIVE=0 -RELOAD=0 UPDATEDB=0 VERIFY=0 @@ -73,7 +73,8 @@ usage() { echo "$(gettext " --import-trustdb Imports ownertrust values from trustdb.gpg in dir(s)")" echo "$(gettext " --init Ensure the keyring is properly initialized")" echo "$(gettext " --list-sigs [] List keys and their signatures")" - echo "$(gettext " --reload Reload the default keys")" + printf "$(gettext " --populate [/dev/null; then + # Verify signatures of keyring files and association revocation files if they exist + msg "$(gettext "Verifying keyring file signatures...")" + local keyring + for keyring in ${KEYRINGIDS[@]}; do + if ! "${GPG_PACMAN[@]}" --verify "${KEYRING_IMPORT_DIR}/${keyring}.gpg.sig" &>/dev/null; then error "$(gettext "The signature of file %s is not valid.")" "${ADDED_KEYS}" ret=1 fi - fi - if [[ -r "${DEPRECATED_KEYS}" ]]; then - msg "$(gettext "Verifying deprecated keys file signature...")" - if ! "${GPG_PACMAN[@]}" --verify "${DEPRECATED_KEYS}.sig" &>/dev/null; then - error "$(gettext "The signature of file %s is not valid.")" "${DEPRECATED_KEYS}" - ret=1 + if [[ -f "${KEYRING_IMPORT_DIR}/${keyring}-revoked" ]]; then + if ! "${GPG_PACMAN[@]}" --verify "${KEYRING_IMPORT_DIR}/${keyring}-revoked.sig" &>/dev/null; then + error "$(gettext "The signature of file %s is not valid.")" "${KEYRING_IMPORT_DIR}/${keyring}-revoked" + ret=1 + fi fi - fi + done - if [[ -r "${REMOVED_KEYS}" ]]; then - msg "$(gettext "Verifying deleted keys file signature...")" - if ! "${GPG_PACMAN[@]}" --verify "${REMOVED_KEYS}.sig" &>/dev/null; then - error "$(gettext "The signature of file %s is not valid.")" "${REMOVED_KEYS}" + return $ret +} + +populate_keyring() { + local KEYRING_IMPORT_DIR='@pkgdatadir@/keyrings' + local GPG_NOKEYRING=(gpg --batch --quiet --ignore-time-conflict --no-options --no-default-keyring --homedir ${PACMAN_KEYRING_DIR} --no-permission-warning) + + local keyring + local ret=0 + if [[ -z ${KEYRINGIDS[@]} ]]; then + # get list of all available keyrings + shopt -s nullglob + KEYRINGIDS=("$KEYRING_IMPORT_DIR"/*.gpg) + shopt -u nullglob + KEYRINGIDS=("${KEYRINGIDS[@]##*/}") + KEYRINGIDS=("${KEYRINGIDS[@]%.gpg}") + if [[ -z ${KEYRINGIDS[@]} ]]; then + error "$(gettext "No keyring files exist in %s.")" "$KEYRING_IMPORT_DIR" ret=1 fi + else + # verify listed keyrings exist + for keyring in ${KEYRINGIDS[@]}; do + if [[ ! -f "$KEYRING_IMPORT_DIR/$keyring.gpg" ]]; then + error "$(gettext "The keyring file %s does not exist.")" "$KEYRING_IMPORT_DIR/$keyring.gpg" + ret=1 + fi + done fi - return $ret -} + if (( ret )); then + exit 1 + fi -reload_keyring() { - local PACMAN_SHARE_DIR='@prefix@/share/pacman' - local GPG_NOKEYRING=(gpg --batch --quiet --ignore-time-conflict --no-options --no-default-keyring --homedir ${PACMAN_KEYRING_DIR}) + verify_keyring_input || exit 1 # Variable used for iterating on keyrings local key local key_id - # Keyring with keys to be added to the keyring - local ADDED_KEYS="${PACMAN_SHARE_DIR}/addedkeys.gpg" - - # Keyring with keys that were deprecated and will eventually be deleted - local DEPRECATED_KEYS="${PACMAN_SHARE_DIR}/deprecatedkeys.gpg" - - # List of keys removed from the keyring. This file is not a keyring, unlike the others. - # It is a textual list of values that gpg recogniezes as identifiers for keys. - local REMOVED_KEYS="${PACMAN_SHARE_DIR}/removedkeys" - - verify_keyring_input || exit 1 - # Read the key ids to an array. The conversion from whatever is inside the file # to key ids is important, because key ids are the only guarantee of identification # for the keys. local -A removed_ids - if [[ -r "${REMOVED_KEYS}" ]]; then - while read key; do - local key_values name - key_values="$("${GPG_PACMAN[@]}" --quiet --with-colons --list-key "${key}" | grep ^pub | cut -d: -f5,10 --output-delimiter=' ')" - if [[ -n $key_values ]]; then - # The first word is the key_id - key_id="${key_values%% *}" - # the rest if the name of the owner - name="${key_values#* }" - if [[ -n ${key_id} ]]; then - # Mark this key to be deleted - removed_ids[$key_id]="$name" + for keyring in ${KEYRINGIDS[@]}; do + if [[ -f "${KEYRING_IMPORT_DIR}/${keyring}-revoked" ]]; then + while read key; do + local key_values name + # extract key ID (field 5) and the name of owner (field 10) + key_values="$("${GPG_PACMAN[@]}" --quiet --with-colons --list-key "${key}" 2>/dev/null | grep ^pub | cut -d: -f5,10 --output-delimiter=' ')" + if [[ -n $key_values ]]; then + # The first word is the key_id + key_id="${key_values%% *}" + # the rest is the name of the owner + name="${key_values#* }" + if [[ -n ${key_id} ]]; then + # Mark this key to be deleted + removed_ids[$key_id]="$name" + fi fi - fi - done < "${REMOVED_KEYS}" - fi + done < "${KEYRING_IMPORT_DIR}/${keyring}-revoked" + fi + done # List of keys that must be kept installed, even if in the list of keys to be removed local HOLD_KEYS="$(get_from "$CONFIG" "HoldKeys")" @@ -222,33 +236,21 @@ reload_keyring() { done fi - # Add keys from the current set of keys from pacman-keyring package. The web of trust will - # be updated automatically. - if [[ -r "${ADDED_KEYS}" ]]; then - msg "$(gettext "Appending official keys...")" - local add_keys="$("${GPG_NOKEYRING[@]}" --keyring "${ADDED_KEYS}" --with-colons --list-keys | grep ^pub | cut -d: -f5)" - for key_id in ${add_keys}; do - # There is no point in adding a key that will be deleted right after - if [[ -z "${removed_ids[$key_id]}" ]]; then - "${GPG_NOKEYRING[@]}" --keyring "${ADDED_KEYS}" --export "${key_id}" | "${GPG_PACMAN[@]}" --import - fi - done - fi - - if [[ -r "${DEPRECATED_KEYS}" ]]; then - msg "$(gettext "Appending deprecated keys...")" - local add_keys="$("${GPG_NOKEYRING[@]}" --keyring "${DEPRECATED_KEYS}" --with-colons --list-keys | grep ^pub | cut -d: -f5)" + # Add keys from requested keyrings + for keyring in ${KEYRINGIDS[@]}; do + msg "$(gettext "Appending keys from %s.gpg...")" "$keyring" + local add_keys="$("${GPG_NOKEYRING[@]}" --keyring "${KEYRING_IMPORT_DIR}/${keyring}.gpg" --with-colons --list-keys | grep ^pub | cut -d: -f5)" for key_id in ${add_keys}; do # There is no point in adding a key that will be deleted right after if [[ -z "${removed_ids[$key_id]}" ]]; then - "${GPG_NOKEYRING[@]}" --keyring "${DEPRECATED_KEYS}" --export "${key_id}" | "${GPG_PACMAN[@]}" --import + "${GPG_NOKEYRING[@]}" --keyring "${KEYRING_IMPORT_DIR}/${keyring}.gpg" --export "${key_id}" | "${GPG_PACMAN[@]}" --import fi done - fi + done # Remove the keys not marked to keep if (( ${#removed_ids[@]} > 0 )); then - msg "$(gettext "Removing deleted keys from keyring...")" + msg "$(gettext "Removing revoked keys from keyring...")" for key_id in "${!removed_ids[@]}"; do echo " removing key $key_id - ${removed_ids[$key_id]}" "${GPG_PACMAN[@]}" --quiet --batch --yes --delete-key "${key_id}" @@ -321,8 +323,8 @@ fi OPT_SHORT="a::d:e:f::hl::r:uv:V" OPT_LONG="add::,config:,delete:,edit-key:,export::,finger::,gpgdir:" -OPT_LONG+=",help,import:,import-trustdb:,init,list-keys::,list-sigs::,,receive:" -OPT_LONG+=",reload,updatedb,verify:,version" +OPT_LONG+=",help,import:,import-trustdb:,init,list-keys::,list-sigs::" +OPT_LONG+=",populate::,receive:,updatedb,verify:,version" if ! OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@")"; then echo; usage; exit 1 # E_INVALID_OPTION; fi @@ -348,8 +350,8 @@ while true; do --init) INIT=1 ;; -l|--list-keys) LISTKEYS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; --list-sigs) LISTSIGS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; + --populate) POPULATE=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYRINGIDS=($1) ;; -r|--receive) RECEIVE=1; shift; TMP=($1); KEYSERVER=${TMP[0]}; KEYIDS=(${TMP[@]:1}); unset TMP;; - --reload) RELOAD=1 ;; -u|--updatedb) UPDATEDB=1 ;; -v|--verify) VERIFY=1; shift; SIGNATURE=$1 ;; @@ -368,7 +370,7 @@ if ! type -p gpg >/dev/null; then exit 1 fi -if (( (ADD || DELETE || EDITKEY || IMPORT || IMPORT_TRUSTDB || INIT || RECEIVE || RELOAD || UPDATEDB) && EUID != 0 )); then +if (( (ADD || DELETE || EDITKEY || IMPORT || IMPORT_TRUSTDB || INIT || POPULATE || RECEIVE || UPDATEDB) && EUID != 0 )); then error "$(gettext "%s needs to be run as root for this operation.")" "pacman-key" exit 1 fi @@ -387,7 +389,7 @@ GPG_PACMAN=(gpg --homedir ${PACMAN_KEYRING_DIR} --no-permission-warning) # check only a single operation has been given numopt=$(( ADD + DELETE + EDITKEY + EXPORT + FINGER + IMPORT + IMPORT_TRUSTDB + - INIT + LISTKEYS + LISTSIGS + RECEIVE + RELOAD + UPDATEDB + VERIFY )) + INIT + LISTKEYS + LISTSIGS + POPULATE + RECEIVE + UPDATEDB + VERIFY )) case $numopt in 0) @@ -413,8 +415,8 @@ esac (( INIT )) && initialize (( LISTKEYS )) && "${GPG_PACMAN[@]}" --batch --list-keys "${KEYIDS[@]}" (( LISTSIGS )) && "${GPG_PACMAN[@]}" --batch --list-sigs "${KEYIDS[@]}" +(( POPULATE )) && populate_keyring (( RECEIVE )) && receive_keys -(( RELOAD )) && reload_keyring (( UPDATEDB )) && "${GPG_PACMAN[@]}" --batch --check-trustdb (( VERIFY )) && "${GPG_PACMAN[@]}" --verify $SIGNATURE -- cgit v1.2.3-54-g00ecf From 710e83999bbf8ae614b9310744c5306a7cbc858b Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Tue, 23 Aug 2011 15:00:19 +1000 Subject: pacman-key: import everything then revoke on --populate The optimization of only importing keys that were not to be later revoked was a not smart enough. For example, if a key was in both a repos keyring and its revoke list, alternate runs of pacman-key --populate would add then remove the key from the pacman keyring. This problem is made worse when considering the possibility of multiple keyrings being imported. Instead, import all keys followed by the revoking of all keys. This may result in a key being added then revoked, but that is not much of an issue given that is a very fast operation. Signed-off-by: Allan McRae --- scripts/pacman-key.sh.in | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 85801006..3e31abbf 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -199,7 +199,16 @@ populate_keyring() { local key local key_id - # Read the key ids to an array. The conversion from whatever is inside the file + # Add keys from requested keyrings + for keyring in ${KEYRINGIDS[@]}; do + msg "$(gettext "Appending keys from %s.gpg...")" "$keyring" + local add_keys="$("${GPG_NOKEYRING[@]}" --keyring "${KEYRING_IMPORT_DIR}/${keyring}.gpg" --with-colons --list-keys | grep ^pub | cut -d: -f5)" + for key_id in ${add_keys}; do + "${GPG_NOKEYRING[@]}" --keyring "${KEYRING_IMPORT_DIR}/${keyring}.gpg" --export "${key_id}" | "${GPG_PACMAN[@]}" --import + done + done + + # Read the revoked key IDs to an array. The conversion from whatever is inside the file # to key ids is important, because key ids are the only guarantee of identification # for the keys. local -A removed_ids @@ -236,18 +245,6 @@ populate_keyring() { done fi - # Add keys from requested keyrings - for keyring in ${KEYRINGIDS[@]}; do - msg "$(gettext "Appending keys from %s.gpg...")" "$keyring" - local add_keys="$("${GPG_NOKEYRING[@]}" --keyring "${KEYRING_IMPORT_DIR}/${keyring}.gpg" --with-colons --list-keys | grep ^pub | cut -d: -f5)" - for key_id in ${add_keys}; do - # There is no point in adding a key that will be deleted right after - if [[ -z "${removed_ids[$key_id]}" ]]; then - "${GPG_NOKEYRING[@]}" --keyring "${KEYRING_IMPORT_DIR}/${keyring}.gpg" --export "${key_id}" | "${GPG_PACMAN[@]}" --import - fi - done - done - # Remove the keys not marked to keep if (( ${#removed_ids[@]} > 0 )); then msg "$(gettext "Removing revoked keys from keyring...")" -- cgit v1.2.3-54-g00ecf From cab1379a1ab14e29414c5fdf6252d1f5ea7263fb Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Tue, 23 Aug 2011 15:12:08 +1000 Subject: pacman-key: update trust database for relevant operations After most operations that touch the keyring, it is a good idea to always run a check on the trustdb as this prevents gpg complaining on later operations. Inspiration-from: Dave Reisner Signed-off-by: Allan McRae --- scripts/pacman-key.sh.in | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 3e31abbf..6a350af6 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -253,10 +253,6 @@ populate_keyring() { "${GPG_PACMAN[@]}" --quiet --batch --yes --delete-key "${key_id}" done fi - - # Update trustdb, just to be sure - msg "$(gettext "Updating trust database...")" - "${GPG_PACMAN[@]}" --batch --check-trustdb } receive_keys() { @@ -335,20 +331,20 @@ fi while true; do case "$1" in - -a|--add) ADD=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYFILES=($1) ;; + -a|--add) ADD=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYFILES=($1); UPDATEDB=1 ;; --config) shift; CONFIG=$1 ;; - -d|--delete) DELETE=1; shift; KEYIDS=($1) ;; - --edit-key) EDITKEY=1; shift; KEYIDS=($1) ;; + -d|--delete) DELETE=1; shift; KEYIDS=($1); UPDATEDB=1 ;; + --edit-key) EDITKEY=1; shift; KEYIDS=($1); UPDATEDB=1 ;; -e|--export) EXPORT=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; -f|--finger) FINGER=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; --gpgdir) shift; PACMAN_KEYRING_DIR=$1 ;; - --import) IMPORT=1; shift; IMPORT_DIRS=($1) ;; - --import-trustdb) IMPORT_TRUSTDB=1; shift; IMPORT_DIRS=($1) ;; + --import) IMPORT=1; shift; IMPORT_DIRS=($1); UPDATEDB=1 ;; + --import-trustdb) IMPORT_TRUSTDB=1; shift; IMPORT_DIRS=($1); UPDATEDB=1 ;; --init) INIT=1 ;; -l|--list-keys) LISTKEYS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; --list-sigs) LISTSIGS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; - --populate) POPULATE=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYRINGIDS=($1) ;; - -r|--receive) RECEIVE=1; shift; TMP=($1); KEYSERVER=${TMP[0]}; KEYIDS=(${TMP[@]:1}); unset TMP;; + --populate) POPULATE=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYRINGIDS=($1); UPDATEDB=1 ;; + -r|--receive) RECEIVE=1; shift; TMP=($1); KEYSERVER=${TMP[0]}; KEYIDS=(${TMP[@]:1}); unset TMP; UPDATEDB=1 ;; -u|--updatedb) UPDATEDB=1 ;; -v|--verify) VERIFY=1; shift; SIGNATURE=$1 ;; @@ -414,7 +410,8 @@ esac (( LISTSIGS )) && "${GPG_PACMAN[@]}" --batch --list-sigs "${KEYIDS[@]}" (( POPULATE )) && populate_keyring (( RECEIVE )) && receive_keys -(( UPDATEDB )) && "${GPG_PACMAN[@]}" --batch --check-trustdb (( VERIFY )) && "${GPG_PACMAN[@]}" --verify $SIGNATURE +(( UPDATEDB )) && "${GPG_PACMAN[@]}" --batch --check-trustdb + # vim: set ts=2 sw=2 noet: -- cgit v1.2.3-54-g00ecf From 29dede2eb76ab5a139d4e8236be1037a7a86b6e5 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Tue, 23 Aug 2011 15:46:46 +1000 Subject: pacman-key: Improve documentation for --populate Signed-off-by: Allan McRae --- doc/pacman-key.8.txt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/doc/pacman-key.8.txt b/doc/pacman-key.8.txt index f61c2eca..ff8d38df 100644 --- a/doc/pacman-key.8.txt +++ b/doc/pacman-key.8.txt @@ -82,10 +82,8 @@ Options *\--populate* []:: Reload the default keys from the (optionally provided) keyrings in - +{pkgdatadir}/keyrings+. Each keyring is provided in a file foo.gpg that - contains the keys for the foo keyring. Optionally the file foo-revoked - contains a list of revoked key IDs for that keyring. These files are - required to be signed (detached) by a trusted PGP key. + +{pkgdatadir}/keyrings+. For more information, see + <> below. *-u, \--updatedb*:: Equivalent to \--check-trustdb in GnuPG. @@ -97,6 +95,19 @@ Options Displays the program version. +Providing a Keyring for Import +------------------------------ +A distribution or other repository provided may want to provide a set of valid +PGP keys used in the signing of its packages and repository databases that can +be readily imported into the pacman keyring. This is achieved by providing a +PGP keyring file `foo.gpg` that contains the keys for the foo keyring in the +directory +{pkgdatadir}/keyrings+. Optionally the file `foo-revoked` can be +provided containing a list of revoked key IDs for that keyring. These files are +required to be signed (detached) by a trusted PGP key that the user must +manually import to the pacman keyring. This prevents a potentially malicious +repository adding keys to the pacman keyring without the users knowledge. + + See Also -------- linkman:pacman[8], linkman:pacman.conf[5] -- cgit v1.2.3-54-g00ecf From e1b9f7b3005c4d6db9cc84e95a42d4beba6c7e24 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Tue, 23 Aug 2011 16:10:06 +1000 Subject: pacman-key: rework and document holding keys in keyring The HoldKey option was undocumented and was not suited for pacman.conf. Instead use the file "/etc/pacman.d/gnupg/heldkeys" to contain a list of keys not to be removed from the pacman keyring with the --populate option. Signed-off-by: Allan McRae --- doc/pacman-key.8.txt | 8 ++++++-- scripts/pacman-key.sh.in | 12 +++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/doc/pacman-key.8.txt b/doc/pacman-key.8.txt index ff8d38df..3582b993 100644 --- a/doc/pacman-key.8.txt +++ b/doc/pacman-key.8.txt @@ -101,12 +101,16 @@ A distribution or other repository provided may want to provide a set of valid PGP keys used in the signing of its packages and repository databases that can be readily imported into the pacman keyring. This is achieved by providing a PGP keyring file `foo.gpg` that contains the keys for the foo keyring in the -directory +{pkgdatadir}/keyrings+. Optionally the file `foo-revoked` can be +directory +{pkgdatadir}/keyrings+. Optionally the file `foo-revoked` can be provided containing a list of revoked key IDs for that keyring. These files are required to be signed (detached) by a trusted PGP key that the user must -manually import to the pacman keyring. This prevents a potentially malicious +manually import to the pacman keyring. This prevents a potentially malicious repository adding keys to the pacman keyring without the users knowledge. +A key being marked as revoked always takes priority over the key being added to +the pacman keyring, regardless of the keyring it is provided in. To prevent a +key from being revoked when using --populate, its ID can be listed in ++{sysconfdir}/pacman.d/gnupg/holdkeys+. See Also -------- diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 6a350af6..7b9f80ba 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -232,17 +232,15 @@ populate_keyring() { fi done - # List of keys that must be kept installed, even if in the list of keys to be removed - local HOLD_KEYS="$(get_from "$CONFIG" "HoldKeys")" - - # Remove the keys that must be kept from the set of keys that should be removed - if [[ -n ${HOLD_KEYS} ]]; then - for key in ${HOLD_KEYS}; do + # Read list of keys that must be kept installed and remove them from the list + # of keys to be removed + if [[ -f "${PACMAN_KEYRING_DIR}/holdkeys" ]]; then + while read key; do key_id="$("${GPG_PACMAN[@]}" --quiet --with-colons --list-key "${key}" | grep ^pub | cut -d: -f5)" if [[ -n "${removed_ids[$key_id]}" ]]; then unset removed_ids[$key_id] fi - done + done < "${PACMAN_KEYRING_DIR}/holdkeys" fi # Remove the keys not marked to keep -- cgit v1.2.3-54-g00ecf From 7ceeebf1505dba655b43e095f5392367a3a0f9b8 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 25 Aug 2011 12:59:26 -0500 Subject: pacman-key: refine permission and locking checks * secring.gpg can be 600, readable by root user only * ensure grep for lock-never option in check_keyring doesn't catch comments Signed-off-by: Dan McGee --- scripts/pacman-key.sh.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 7b9f80ba..1c93314c 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -109,7 +109,8 @@ initialize() { [[ -f ${PACMAN_KEYRING_DIR}/pubring.gpg ]] || touch ${PACMAN_KEYRING_DIR}/pubring.gpg [[ -f ${PACMAN_KEYRING_DIR}/secring.gpg ]] || touch ${PACMAN_KEYRING_DIR}/secring.gpg [[ -f ${PACMAN_KEYRING_DIR}/trustdb.gpg ]] || "${GPG_PACMAN[@]}" --update-trustdb - chmod 644 ${PACMAN_KEYRING_DIR}/{{pub,sec}ring,trustdb}.gpg + chmod 644 ${PACMAN_KEYRING_DIR}/{pubring,trustdb}.gpg + chmod 600 ${PACMAN_KEYRING_DIR}/secring.gpg # gpg.conf [[ -f ${PACMAN_KEYRING_DIR}/gpg.conf ]] || touch ${PACMAN_KEYRING_DIR}/gpg.conf @@ -121,7 +122,6 @@ initialize() { check_keyring() { if [[ ! -r ${PACMAN_KEYRING_DIR}/pubring.gpg || \ - ! -r ${PACMAN_KEYRING_DIR}/secring.gpg || \ ! -r ${PACMAN_KEYRING_DIR}/trustdb.gpg ]]; then error "$(gettext "You do not have sufficient permissions to read the %s keyring...")" "pacman" msg "$(gettext "Use '%s' to correct the keyring permissions.")" "pacman-key --init" @@ -129,7 +129,7 @@ check_keyring() { fi if (( (EXPORT || FINGER || LIST || VERIFY) && EUID != 0 )); then - if ! grep -w -q "lock-never" ${PACMAN_KEYRING_DIR}/gpg.conf &>/dev/null; then + if ! grep -q "^[[:space:]]*lock-never[[:space:]]*$" ${PACMAN_KEYRING_DIR}/gpg.conf &>/dev/null; then error "$(gettext "You do not have sufficient permissions to run this command...")" msg "$(gettext "Use '%s' to correct the keyring permissions.")" "pacman-key --init" exit 1 -- cgit v1.2.3-54-g00ecf From 12a6c77fdd0c465761f4f9518eff0eeeda668d20 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 25 Aug 2011 12:59:27 -0500 Subject: pacman-key: have --init add more options to default gpg.conf This adds a add_gpg_conf_option() helper function which tries to be intelligent and only add not found options, and those which have not been explicitly commented out. The new options added are 'no-greeting', 'no-permission-warning', and a default 'keyserver'. Signed-off-by: Dan McGee --- scripts/pacman-key.sh.in | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 1c93314c..fb42f938 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -100,7 +100,22 @@ get_from() { return 1 } +# Adds the given gpg.conf option if it is not present in the file. +# Note that if we find it commented out, we won't add the option. +# args: $1 conffile, $2 option-name, $3 (optional) option-value +add_gpg_conf_option() { + local confline + # looking for the option 'bare', only leading spaces or # chars allowed, + # followed by at least one space and any other text or the end of line. + if ! grep -q "^[[:space:]#]*$2\([[:space:]].*\)*$" "$1" &>/dev/null; then + confline="$2" + [[ -n $3 ]] && confline="$2 $3" + echo "$confline" >> "$1" + fi +} + initialize() { + local conffile # Check for simple existence rather than for a directory as someone # may want to use a symlink here [[ -e ${PACMAN_KEYRING_DIR} ]] || mkdir -p -m 755 "${PACMAN_KEYRING_DIR}" @@ -113,11 +128,13 @@ initialize() { chmod 600 ${PACMAN_KEYRING_DIR}/secring.gpg # gpg.conf - [[ -f ${PACMAN_KEYRING_DIR}/gpg.conf ]] || touch ${PACMAN_KEYRING_DIR}/gpg.conf - chmod 644 ${PACMAN_KEYRING_DIR}/gpg.conf - if ! grep -w -q "lock-never" ${PACMAN_KEYRING_DIR}/gpg.conf &>/dev/null; then - echo "lock-never" >> ${PACMAN_KEYRING_DIR}/gpg.conf - fi + conffile="${PACMAN_KEYRING_DIR}/gpg.conf" + [[ -f $conffile ]] || touch "$conffile" + chmod 644 "$conffile" + add_gpg_conf_option "$conffile" 'no-greeting' + add_gpg_conf_option "$conffile" 'no-permission-warning' + add_gpg_conf_option "$conffile" 'lock-never' + add_gpg_conf_option "$conffile" 'keyserver' 'hkp://keys.gnupg.net' } check_keyring() { -- cgit v1.2.3-54-g00ecf