Просмотр исходного кода

use only one --keyring in gpg interactions

We were down to at most two keyrings before, but gnupg upstream plans
dropping support for multiple keyrings in the longrun, so with a
single keyring we hope to be future proof – and 'apt-key adv' isn't a
problem anymore as every change to the keys is merged back, so we have
now the same behavior as before, but support an unlimited amount of
trusted.gpg.d keyrings.
David Kalnischkies лет назад: 12
Родитель
Сommit
0dae96a2b5
2 измененных файлов с 116 добавлено и 46 удалено
  1. 77 28
      cmdline/apt-key.in
  2. 39 18
      test/integration/test-apt-key

+ 77 - 28
cmdline/apt-key.in

@@ -14,7 +14,6 @@ REMOVED_KEYS='&keyring-removed-filename;'
 eval $(apt-config shell REMOVED_KEYS APT::Key::RemovedKeys)
 eval $(apt-config shell REMOVED_KEYS APT::Key::RemovedKeys)
 ARCHIVE_KEYRING_URI='&keyring-uri;'
 ARCHIVE_KEYRING_URI='&keyring-uri;'
 eval $(apt-config shell ARCHIVE_KEYRING_URI APT::Key::ArchiveKeyringURI)
 eval $(apt-config shell ARCHIVE_KEYRING_URI APT::Key::ArchiveKeyringURI)
-TMP_KEYRING=${APT_DIR}/var/lib/apt/keyrings/maybe-import-keyring.gpg
 
 
 aptkey_echo() { echo "$@"; }
 aptkey_echo() { echo "$@"; }
 
 
@@ -68,24 +67,28 @@ add_keys_with_verify_against_master_keyring() {
             fi
             fi
         done
         done
     done
     done
-    
+
     for add_key in $add_keys; do
     for add_key in $add_keys; do
         # export the add keyring one-by-one
         # export the add keyring one-by-one
-        rm -f $TMP_KEYRING
-        $GPG_CMD --keyring $ADD_KEYRING --output $TMP_KEYRING --export $add_key 
-        # check if signed with the master key and only add in this case
-        ADDED=0
+	local TMP_KEYRING="${GPGHOMEDIR}/tmp-keyring.gpg"
+	$GPG_CMD --batch --yes --keyring "$ADD_KEYRING" --output "$TMP_KEYRING" --export "$add_key"
+	if ! $GPG_CMD --batch --yes --keyring "$TMP_KEYRING" --import "$MASTER" > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
+	    cat "${GPGHOMEDIR}/gpgoutput.log"
+	    false
+	fi
+	# check if signed with the master key and only add in this case
+	ADDED=0
 	for master_key in $master_keys; do
 	for master_key in $master_keys; do
-	    if $GPG_CMD --keyring $MASTER --keyring $TMP_KEYRING --check-sigs --with-colons $add_key | grep '^sig:!:' | cut -d: -f5 | grep -q $master_key; then
-		$GPG --import $TMP_KEYRING
+	    if $GPG_CMD --keyring $TMP_KEYRING --check-sigs --with-colons $add_key | grep '^sig:!:' | cut -d: -f5 | grep -q $master_key; then
+		$GPG_CMD --batch --yes --keyring "$ADD_KEYRING" --export "$add_key" | $GPG --batch --yes --import
 		ADDED=1
 		ADDED=1
 	    fi
 	    fi
 	done
 	done
 	if [ $ADDED = 0 ]; then
 	if [ $ADDED = 0 ]; then
 	    echo >&2 "Key '$add_key' not added. It is not signed with a master key"
 	    echo >&2 "Key '$add_key' not added. It is not signed with a master key"
 	fi
 	fi
+	rm -f "${TMP_KEYRING}"
     done
     done
-    rm -f $TMP_KEYRING
 }
 }
 
 
 # update the current archive signing keyring from a network URI
 # update the current archive signing keyring from a network URI
@@ -240,26 +243,75 @@ fingerprint_keys_from_keyring() {
 import_keys_from_keyring() {
 import_keys_from_keyring() {
     local IMPORT="$1"
     local IMPORT="$1"
     local KEYRINGFILE="$2"
     local KEYRINGFILE="$2"
-    $GPG_CMD --keyring "$KEYRINGFILE" --batch --import "$IMPORT" >/dev/null 2>&1
+    if ! $GPG_CMD --keyring "$KEYRINGFILE" --batch --import "$IMPORT" > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
+	cat "${GPGHOMEDIR}/gpgoutput.log"
+	false
+    fi
+}
+
+merge_keys_into_keyrings() {
+    local KEYRINGFILE="$1"
+    local IMPORT="$2"
+    if ! $GPG_CMD --keyring "$KEYRINGFILE" --batch --import --import-options 'merge-only' "$IMPORT" > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
+	cat "${GPGHOMEDIR}/gpgoutput.log"
+	false
+    fi
+}
+
+merge_back_changes() {
+    if [ -n "$FORCED_KEYRING" ]; then
+	# if the keyring was forced merge is already done
+	return
+    fi
+    if [ -s "${GPGHOMEDIR}/pubring.gpg" ]; then
+	# merge all updated keys
+	foreach_keyring_do 'merge_keys_into_keyrings' "${GPGHOMEDIR}/pubring.gpg"
+    fi
+    # no look for keys which were added or removed
+    get_fingerprints_of_keyring "${GPGHOMEDIR}/pubring.orig.gpg" > "${GPGHOMEDIR}/pubring.orig.keylst"
+    get_fingerprints_of_keyring "${GPGHOMEDIR}/pubring.gpg" > "${GPGHOMEDIR}/pubring.keylst"
+    #echo >&2 "MERGE BACK"
+    sort "${GPGHOMEDIR}/pubring.keylst" "${GPGHOMEDIR}/pubring.orig.keylst" | uniq --unique | while read key; do
+	if grep -q "^${key}$" "${GPGHOMEDIR}/pubring.orig.keylst"; then
+	    # key isn't part of new keyring, so remove
+	    foreach_keyring_do 'remove_key_from_keyring' "$key"
+	elif grep -q "^${key}$" "${GPGHOMEDIR}/pubring.keylst"; then
+	    # key is part of new keyring, so we need to import it
+	    create_new_keyring "$TRUSTEDFILE"
+	    if ! $GPG --batch --yes --export "$key" | $GPG_CMD --keyring "$TRUSTEDFILE" --batch --yes --import > "${GPGHOMEDIR}/gpgoutput.log" 2>&1; then
+	       cat "${GPGHOMEDIR}/gpgoutput.log"
+	       false
+	    fi
+	else
+	    echo >&2 "Errror: Key ${key} (dis)appeared out of nowhere"
+	fi
+    done
 }
 }
 
 
 setup_merged_keyring() {
 setup_merged_keyring() {
     if [ -z "$FORCED_KEYRING" ]; then
     if [ -z "$FORCED_KEYRING" ]; then
-	local TRUSTEDFILE_BAK="$TRUSTEDFILE"
-	TRUSTEDFILE='/dev/null'
 	foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/pubring.gpg"
 	foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/pubring.gpg"
-	TRUSTEDFILE="$TRUSTEDFILE_BAK"
-	# mark it as non-writeable so users get errors if gnupg tries to modify it
-	if [ -s "${GPGHOMEDIR}/pubring.gpg" ]; then
-	    chmod -w "${GPGHOMEDIR}/pubring.gpg"
-	    GPG="$GPG --keyring ${GPGHOMEDIR}/pubring.gpg"
+	if [ -r "${GPGHOMEDIR}/pubring.gpg" ]; then
+	    cp -a "${GPGHOMEDIR}/pubring.gpg" "${GPGHOMEDIR}/pubring.orig.gpg"
+	else
+	   touch "${GPGHOMEDIR}/pubring.gpg" "${GPGHOMEDIR}/pubring.orig.gpg"
 	fi
 	fi
-    fi
-    if [ -r "$TRUSTEDFILE" ]; then
-	GPG="$GPG --keyring $TRUSTEDFILE --primary-keyring $TRUSTEDFILE"
+	GPG="$GPG --keyring ${GPGHOMEDIR}/pubring.gpg"
+    else
+	GPG="$GPG --keyring $TRUSTEDFILE"
+	create_new_keyring "$TRUSTEDFILE"
     fi
     fi
 }
 }
 
 
+create_new_keyring() {
+    # gpg defaults to mode 0600 for new keyrings. Create one with 0644 instead.
+    if ! [ -e "$TRUSTEDFILE" ]; then
+	if [ -w "$(dirname "$TRUSTEDFILE")" ]; then
+	    touch -- "$TRUSTEDFILE"
+	    chmod 0644 -- "$TRUSTEDFILE"
+	fi
+    fi
+}
 
 
 usage() {
 usage() {
     echo "Usage: apt-key [--keyring file] [command] [arguments]"
     echo "Usage: apt-key [--keyring file] [command] [arguments]"
@@ -365,14 +417,6 @@ if [ "$command" != "help" ]; then
 	rm -f "$SECRETKEYRING"
 	rm -f "$SECRETKEYRING"
 	cp -a "$FORCED_SECRET_KEYRING" "$SECRETKEYRING"
 	cp -a "$FORCED_SECRET_KEYRING" "$SECRETKEYRING"
     fi
     fi
-
-    # gpg defaults to mode 0600 for new keyrings. Create one with 0644 instead.
-    if ! [ -e "$TRUSTEDFILE" ]; then
-	if [ -w "$(dirname "$TRUSTEDFILE")" ]; then
-	   touch -- "$TRUSTEDFILE"
-	   chmod 0644 -- "$TRUSTEDFILE"
-	fi
-    fi
 fi
 fi
 
 
 case "$command" in
 case "$command" in
@@ -380,22 +424,26 @@ case "$command" in
 	requires_root
 	requires_root
 	setup_merged_keyring
 	setup_merged_keyring
 	$GPG --quiet --batch --import "$@"
 	$GPG --quiet --batch --import "$@"
+	merge_back_changes
 	aptkey_echo "OK"
 	aptkey_echo "OK"
         ;;
         ;;
     del|rm|remove)
     del|rm|remove)
 	requires_root
 	requires_root
 	foreach_keyring_do 'remove_key_from_keyring' "$@"
 	foreach_keyring_do 'remove_key_from_keyring' "$@"
+	merge_back_changes
 	aptkey_echo "OK"
 	aptkey_echo "OK"
         ;;
         ;;
     update)
     update)
 	requires_root
 	requires_root
 	setup_merged_keyring
 	setup_merged_keyring
 	update
 	update
+	merge_back_changes
 	;;
 	;;
     net-update)
     net-update)
 	requires_root
 	requires_root
 	setup_merged_keyring
 	setup_merged_keyring
 	net_update
 	net_update
+	merge_back_changes
 	;;
 	;;
     list)
     list)
 	foreach_keyring_do 'list_keys_from_keyring' "$@"
 	foreach_keyring_do 'list_keys_from_keyring' "$@"
@@ -411,6 +459,7 @@ case "$command" in
 	setup_merged_keyring
 	setup_merged_keyring
 	aptkey_echo "Executing: $GPG $*"
 	aptkey_echo "Executing: $GPG $*"
 	$GPG "$@"
 	$GPG "$@"
+	merge_back_changes
 	;;
 	;;
     help)
     help)
         usage
         usage

+ 39 - 18
test/integration/test-apt-key

@@ -13,6 +13,13 @@ cleanplate() {
 	mkdir rootdir/etc/apt/trusted.gpg.d/
 	mkdir rootdir/etc/apt/trusted.gpg.d/
 }
 }
 
 
+testaptkeys() {
+	if ! aptkey list | grep '^pub' > aptkey.list; then
+		echo -n > aptkey.list
+	fi
+	testequal "$1" cat ./aptkey.list
+}
+
 echo 'APT::Key::ArchiveKeyring "./keys/joesixpack.pub";
 echo 'APT::Key::ArchiveKeyring "./keys/joesixpack.pub";
 APT::Key::RemovedKeys "./keys/rexexpired.pub";' > rootdir/etc/apt/apt.conf.d/aptkey.conf
 APT::Key::RemovedKeys "./keys/rexexpired.pub";' > rootdir/etc/apt/apt.conf.d/aptkey.conf
 
 
@@ -26,20 +33,17 @@ testrun() {
 	msgtest 'Check that paths in finger output are not' 'double-slashed'
 	msgtest 'Check that paths in finger output are not' 'double-slashed'
 	aptkey finger 2>&1 | grep -q '//' && msgfail || msgpass
 	aptkey finger 2>&1 | grep -q '//' && msgfail || msgpass
 
 
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/DBAC8DAE 2010-08-18'
+	testaptkeys 'pub   2048R/DBAC8DAE 2010-08-18'
 
 
 	testequal 'gpg: key DBAC8DAE: "Joe Sixpack (APT Testcases Dummy) <joe@example.org>" not changed
 	testequal 'gpg: key DBAC8DAE: "Joe Sixpack (APT Testcases Dummy) <joe@example.org>" not changed
 gpg: Total number processed: 1
 gpg: Total number processed: 1
 gpg:              unchanged: 1' aptkey --fakeroot update
 gpg:              unchanged: 1' aptkey --fakeroot update
 
 
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/DBAC8DAE 2010-08-18'
+	testaptkeys 'pub   2048R/DBAC8DAE 2010-08-18'
 
 
 	testsuccess aptkey --fakeroot add ./keys/rexexpired.pub
 	testsuccess aptkey --fakeroot add ./keys/rexexpired.pub
 
 
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/27CE74F9 2013-07-12 [expired: 2013-07-13]
+	testaptkeys 'pub   2048R/27CE74F9 2013-07-12 [expired: 2013-07-13]
 pub   2048R/DBAC8DAE 2010-08-18'
 pub   2048R/DBAC8DAE 2010-08-18'
 
 
 	msgtest 'Check that Sixpack key can be' 'exported'
 	msgtest 'Check that Sixpack key can be' 'exported'
@@ -52,14 +56,12 @@ pub   2048R/DBAC8DAE 2010-08-18'
 	msgtest 'Execute update again to trigger removal of' 'Rex Expired key'
 	msgtest 'Execute update again to trigger removal of' 'Rex Expired key'
 	testsuccess --nomsg aptkey --fakeroot update
 	testsuccess --nomsg aptkey --fakeroot update
 
 
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/DBAC8DAE 2010-08-18'
+	testaptkeys 'pub   2048R/DBAC8DAE 2010-08-18'
 
 
 	msgtest "Try to remove a key which exists, but isn't in the" 'forced keyring'
 	msgtest "Try to remove a key which exists, but isn't in the" 'forced keyring'
 	testsuccess --nomsg aptkey --fakeroot --keyring rootdir/etc/apt/trusted.gpg del DBAC8DAE
 	testsuccess --nomsg aptkey --fakeroot --keyring rootdir/etc/apt/trusted.gpg del DBAC8DAE
 
 
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/DBAC8DAE 2010-08-18'
+	testaptkeys 'pub   2048R/DBAC8DAE 2010-08-18'
 
 
 	testsuccess aptkey --fakeroot del DBAC8DAE
 	testsuccess aptkey --fakeroot del DBAC8DAE
 	testempty aptkey list
 	testempty aptkey list
@@ -91,8 +93,7 @@ pub   2048R/DBAC8DAE 2010-08-18'
 	cleanplate
 	cleanplate
 	testsuccess aptkey --fakeroot add ./keys/joesixpack.pub
 	testsuccess aptkey --fakeroot add ./keys/joesixpack.pub
 	testsuccess aptkey --fakeroot add ./keys/marvinparanoid.pub
 	testsuccess aptkey --fakeroot add ./keys/marvinparanoid.pub
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/DBAC8DAE 2010-08-18
+	testaptkeys 'pub   2048R/DBAC8DAE 2010-08-18
 pub   2048R/528144E2 2011-01-16'
 pub   2048R/528144E2 2011-01-16'
 	cp -a rootdir/etc/apt/trusted.gpg keys/testcase-multikey.pub # store for reuse
 	cp -a rootdir/etc/apt/trusted.gpg keys/testcase-multikey.pub # store for reuse
 
 
@@ -100,16 +101,14 @@ pub   2048R/528144E2 2011-01-16'
 	cleanplate
 	cleanplate
 	cp -a keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	cp -a keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	testsuccess --nomsg aptkey --fakeroot del DBAC8DAE
 	testsuccess --nomsg aptkey --fakeroot del DBAC8DAE
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/528144E2 2011-01-16'
+	testaptkeys 'pub   2048R/528144E2 2011-01-16'
 	testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
 	testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
 
 
 	msgtest 'Test key removal with' 'multi key in softlink'
 	msgtest 'Test key removal with' 'multi key in softlink'
 	cleanplate
 	cleanplate
 	ln -s $(readlink -f ./keys/testcase-multikey.pub) rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	ln -s $(readlink -f ./keys/testcase-multikey.pub) rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	testsuccess --nomsg aptkey --fakeroot del DBAC8DAE
 	testsuccess --nomsg aptkey --fakeroot del DBAC8DAE
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/528144E2 2011-01-16'
+	testaptkeys 'pub   2048R/528144E2 2011-01-16'
 	testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
 	testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
 	testsuccess test ! -L rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	testsuccess test ! -L rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	testsuccess test -L rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
 	testsuccess test -L rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
@@ -119,11 +118,33 @@ pub   2048R/528144E2 2011-01-16'
 	cp -a keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
 	cp -a keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
 	cp -a keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	cp -a keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg
 	testsuccess --nomsg aptkey --fakeroot del DBAC8DAE
 	testsuccess --nomsg aptkey --fakeroot del DBAC8DAE
-	aptkey list | grep '^pub' > aptkey.list
-	testfileequal ./aptkey.list 'pub   2048R/528144E2 2011-01-16'
+	testaptkeys 'pub   2048R/528144E2 2011-01-16'
 	testsuccess test ! -e rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
 	testsuccess test ! -e rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
 	testsuccess cmp keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg~
 	testsuccess cmp keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg~
 	testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
 	testsuccess cmp keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg~
+
+	cleanplate
+	cp -a keys/joesixpack.pub rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
+	cp -a keys/testcase-multikey.pub rootdir/etc/apt/trusted.gpg.d/multikey.gpg
+	testaptkeys 'pub   2048R/DBAC8DAE 2010-08-18
+pub   2048R/DBAC8DAE 2010-08-18
+pub   2048R/528144E2 2011-01-16'
+	msgtest 'Test merge-back of' 'added keys'
+	testsuccess --nomsg aptkey adv --batch --yes --import keys/rexexpired.pub
+	testaptkeys 'pub   2048R/27CE74F9 2013-07-12 [expired: 2013-07-13]
+pub   2048R/DBAC8DAE 2010-08-18
+pub   2048R/DBAC8DAE 2010-08-18
+pub   2048R/528144E2 2011-01-16'
+
+	msgtest 'Test merge-back of' 'removed keys'
+	testsuccess --nomsg aptkey adv --batch --yes --delete-keys 27CE74F9
+	testaptkeys 'pub   2048R/DBAC8DAE 2010-08-18
+pub   2048R/DBAC8DAE 2010-08-18
+pub   2048R/528144E2 2011-01-16'
+
+	msgtest 'Test merge-back of' 'removed duplicate keys'
+	testsuccess --nomsg aptkey adv --batch --yes --delete-keys DBAC8DAE
+	testaptkeys 'pub   2048R/528144E2 2011-01-16'
 }
 }
 
 
 setupgpgcommand() {
 setupgpgcommand() {