[pacman-dev] [PATCH v2] pacman-key: --refresh-keys queries WKD before keyserver
From: Morten Linderud <morten@linderud.pw> With the recent outages of the keyservers there is a possibility of `--refresh-keys` failing to fetch new keys. A lot of current key distribution is done over WKD these days, and `pacman-key` has the ability to use it for `--recv-key`. There was a hope `gpg` would end up supporting WKD for the refresh functionality, but this seems to be limited to expired keys fetched through WKD. Since this functionality isn't yet available it makes sense to stuff it into `pacman-key`. The current implementation looks over all available keyids in the keyring, attempts to fetch over WKD and then fall backs to keyservers if no email has a valid WKD available. The downside of this approach is that it takes a bit longer to refresh the keys, but it should be more robust as the distribution should be providing their own WKDs. Co-authored-by: Jonas Witschel <diabonas@archlinux.org> Signed-off-by: Morten Linderud <morten@linderud.pw> --- * Done grep -vx * Removed the redundant error since it's caught by `check_keyids_exist` * Improved the error message with the keyid scripts/pacman-key.sh.in | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index c65669f5..e89d7af9 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -540,11 +540,36 @@ receive_keys() { } refresh_keys() { + local ret=0 ids masterkey emails + check_keyids_exist "$@" - if ! "${GPG_PACMAN[@]}" --refresh-keys "$@" ; then - error "$(gettext "A specified local key could not be updated from a keyserver.")" - exit 1 - fi + + # don't try to refresh the user's local masterkey + masterkey="$("${GPG_PACMAN[@]}" --list-keys --with-colons pacman@localhost | + awk -F: '$1 == "pub" { print $5 }')" + + mapfile -t ids < \ + <("${GPG_PACMAN[@]}" --list-keys --with-colons "$@" | + awk -F: '$1 == "pub" { print $5 }' | grep -vx "$masterkey") + + for id in "${ids[@]}"; do + mapfile -t emails < \ + <("${GPG_PACMAN[@]}" --list-keys --list-options show-only-fpr-mbox "$id" | + awk '{print $2 }') + + # first try looking up the key in a WKD (only works by email address) + for email in "${emails[@]}"; do + "${GPG_PACMAN[@]}" --locate-external-keys "$email" && break + done + + # if no key was found, fall back to using the keyservers (with the key fingerprint instead) + if (( $? )) && ! "${GPG_PACMAN[@]}" --refresh-keys "$id"; then + error "$(gettext "The following key could not be updated from WKD or keyserver: %s")" "$id" + ret=1 + fi + done + + exit $ret } verify_sig() { -- 2.30.1
On 22/2/21 9:09 am, Morten Linderud wrote:
From: Morten Linderud <morten@linderud.pw>
With the recent outages of the keyservers there is a possibility of `--refresh-keys` failing to fetch new keys. A lot of current key distribution is done over WKD these days, and `pacman-key` has the ability to use it for `--recv-key`.
There was a hope `gpg` would end up supporting WKD for the refresh functionality, but this seems to be limited to expired keys fetched through WKD. Since this functionality isn't yet available it makes sense to stuff it into `pacman-key`.
The current implementation looks over all available keyids in the keyring, attempts to fetch over WKD and then fall backs to keyservers if no email has a valid WKD available. The downside of this approach is that it takes a bit longer to refresh the keys, but it should be more robust as the distribution should be providing their own WKDs.
Co-authored-by: Jonas Witschel <diabonas@archlinux.org> Signed-off-by: Morten Linderud <morten@linderud.pw> ---
* Done grep -vx
* Removed the redundant error since it's caught by `check_keyids_exist`
* Improved the error message with the keyid
scripts/pacman-key.sh.in | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index c65669f5..e89d7af9 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -540,11 +540,36 @@ receive_keys() { }
refresh_keys() { + local ret=0 ids masterkey emails + check_keyids_exist "$@" - if ! "${GPG_PACMAN[@]}" --refresh-keys "$@" ; then - error "$(gettext "A specified local key could not be updated from a keyserver.")" - exit 1 - fi + + # don't try to refresh the user's local masterkey + masterkey="$("${GPG_PACMAN[@]}" --list-keys --with-colons pacman@localhost | + awk -F: '$1 == "pub" { print $5 }')" + + mapfile -t ids < \ + <("${GPG_PACMAN[@]}" --list-keys --with-colons "$@" | + awk -F: '$1 == "pub" { print $5 }' | grep -vx "$masterkey") + + for id in "${ids[@]}"; do + mapfile -t emails < \ + <("${GPG_PACMAN[@]}" --list-keys --list-options show-only-fpr-mbox "$id" | + awk '{print $2 }') + + # first try looking up the key in a WKD (only works by email address) + for email in "${emails[@]}"; do + "${GPG_PACMAN[@]}" --locate-external-keys "$email" && break + done + + # if no key was found, fall back to using the keyservers (with the key fingerprint instead) + if (( $? )) && ! "${GPG_PACMAN[@]}" --refresh-keys "$id"; then + error "$(gettext "The following key could not be updated from WKD or keyserver: %s")" "$id"
This error message is verbose. "The following key..." is not needed. It would be strange if we listed the key id not associated with the message! And the user does not care that both WKD and keyserver failed, just that there is a failure. How about: error "$(gettext "Could not update key: %s") "$id"
+ ret=1 + fi + done + + exit $ret }
verify_sig() {
On Wed, Feb 24, 2021 at 10:57:47PM +1000, Allan McRae wrote:
On 22/2/21 9:09 am, Morten Linderud wrote:
From: Morten Linderud <morten@linderud.pw> + # if no key was found, fall back to using the keyservers (with the key fingerprint instead) + if (( $? )) && ! "${GPG_PACMAN[@]}" --refresh-keys "$id"; then + error "$(gettext "The following key could not be updated from WKD or keyserver: %s")" "$id"
This error message is verbose. "The following key..." is not needed. It would be strange if we listed the key id not associated with the message! And the user does not care that both WKD and keyserver failed, just that there is a failure.
How about:
error "$(gettext "Could not update key: %s") "$id"
Ack! Looks good to me! -- Morten Linderud PGP: 9C02FF419FECBE16
On 2/24/21 7:57 AM, Allan McRae wrote:
On 22/2/21 9:09 am, Morten Linderud wrote:
From: Morten Linderud <morten@linderud.pw>
With the recent outages of the keyservers there is a possibility of `--refresh-keys` failing to fetch new keys. A lot of current key distribution is done over WKD these days, and `pacman-key` has the ability to use it for `--recv-key`.
There was a hope `gpg` would end up supporting WKD for the refresh functionality, but this seems to be limited to expired keys fetched through WKD. Since this functionality isn't yet available it makes sense to stuff it into `pacman-key`.
The current implementation looks over all available keyids in the keyring, attempts to fetch over WKD and then fall backs to keyservers if no email has a valid WKD available. The downside of this approach is that it takes a bit longer to refresh the keys, but it should be more robust as the distribution should be providing their own WKDs.
Co-authored-by: Jonas Witschel <diabonas@archlinux.org> Signed-off-by: Morten Linderud <morten@linderud.pw> ---
* Done grep -vx
* Removed the redundant error since it's caught by `check_keyids_exist`
* Improved the error message with the keyid
scripts/pacman-key.sh.in | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index c65669f5..e89d7af9 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -540,11 +540,36 @@ receive_keys() { }
refresh_keys() { + local ret=0 ids masterkey emails + check_keyids_exist "$@" - if ! "${GPG_PACMAN[@]}" --refresh-keys "$@" ; then - error "$(gettext "A specified local key could not be updated from a keyserver.")" - exit 1 - fi + + # don't try to refresh the user's local masterkey + masterkey="$("${GPG_PACMAN[@]}" --list-keys --with-colons pacman@localhost | + awk -F: '$1 == "pub" { print $5 }')" + + mapfile -t ids < \ + <("${GPG_PACMAN[@]}" --list-keys --with-colons "$@" | + awk -F: '$1 == "pub" { print $5 }' | grep -vx "$masterkey") + + for id in "${ids[@]}"; do + mapfile -t emails < \ + <("${GPG_PACMAN[@]}" --list-keys --list-options show-only-fpr-mbox "$id" | + awk '{print $2 }') + + # first try looking up the key in a WKD (only works by email address) + for email in "${emails[@]}"; do + "${GPG_PACMAN[@]}" --locate-external-keys "$email" && break + done + + # if no key was found, fall back to using the keyservers (with the key fingerprint instead) + if (( $? )) && ! "${GPG_PACMAN[@]}" --refresh-keys "$id"; then + error "$(gettext "The following key could not be updated from WKD or keyserver: %s")" "$id"
This error message is verbose. "The following key..." is not needed. It would be strange if we listed the key id not associated with the message! And the user does not care that both WKD and keyserver failed, just that there is a failure.
How about:
error "$(gettext "Could not update key: %s") "$id"
https://bugs.archlinux.org/task/69865 :p
+ ret=1 + fi + done + + exit $ret }
verify_sig() {
-- Eli Schwartz Bug Wrangler and Trusted User
participants (3)
-
Allan McRae
-
Eli Schwartz
-
Morten Linderud