`repair-keys` does not reorder signatures on non-merge imports
Open, NormalPublic

Description

because repair-keys is supposed to default to yes, i'd expect import-export to reorder signatures, and i'd expect an import into an empty keyring to reorder signatures.

However, it does not appear to do so.

In particular, if i strip down an OpenPGP certificate to just the smallest possible transferable public key (no subkeys, no third-party certifications, just primary key+userid+selfsig), import that thing into a keyring, and then import the full certificate again and then re-export it, the signatures do get re-ordered.

But if i just use import-export, they do not get re-ordered.

So something about the merge operation is causing repair-keys to behave differently.

Details

Version
2.2.14
dkg created this task.Mar 23 2019, 1:28 AM
dkg added a comment.Mar 23 2019, 1:51 AM

Here is a horrible bash function for doing the kind of stripping and re-importing that *does* cause signature re-ordering:

# takes name of transferable public key file as $1, emits the laundered key to file named $2
launder_tpk() {
    local interim="$(mktemp -d interim.XXXXXXX)"
    local success=false
    local key="$1"
    local output="$2"
    mkdir -p -m 0700 "$interim/gpg" "$interim/split"
    cat > "$interim/gpg/gpg.conf" <<EOF
batch
no-tty
quiet
no-options
trust-model always
fixed-list-mode
with-colons
EOF
    if gpg --homedir "$interim/gpg" --import-options=import-minimal --status-file "$interim/status" --import < "$key" &&
            fpr="$(awk '{ if ($1 == "[GNUPG:]" && $2 == "IMPORT_OK" && $3 == "1") { print $4 } }' < "$interim/status")" &&
            gpg --homedir "$interim/gpg" --export | (cd "$interim/split" && gpgsplit) &&
            gpg --homedir "$interim/gpg" --delete-key "$fpr"; then
        local pub="$interim/split/000001-006.public_key"
        local uid=$(ls "$interim/split/"*.user_id | head -n1)
        local sig=$(printf '%s/split/%06d-002.sig' "$interim" $(( "$(echo "${uid##$interim/split/}" | sed -e 's_^0*__' -e 's_-.*$__')" + 1 )) )
        if [ -r "$pub" ] && [ -r "$uid" ] && [ -r "$sig" ]; then
            if cat "$pub" "$uid" "$sig" | gpg --homedir "$interim/gpg" --import &&
                    gpg --homedir "$interim/gpg" --import < "$key" &&
                    gpg --homedir "$interim/gpg" --output "$output" --export "$fpr"; then
                success=true
            fi
        else
            printf 'Could not find minimal TPK for %s\n' "$fpr" >&2
        fi
    fi
    rm -rf "$interim"
    [ $success = true ]
}
dkg added a comment.Mar 23 2019, 1:55 AM

as i experiment with this, i find an even weirder result with certificate re-ordering: the function above is not idempotent.

The attached file will cycle between two states if you launder_tpk it repeatedly:

0 dkg@alice:~$ launder_tpk tmp/test0.pgp tmp/test1.pgp
0 dkg@alice:~$ launder_tpk tmp/test1.pgp tmp/test2.pgp
0 dkg@alice:~$ sha256sum tmp/test{0,1,2}.pgp
24f337938dbad3088722f395bca80d17d2ca672ad0b9181838ad4a09029d0711  tmp/test0.pgp
99a6ab1927ac09795f1ec5610cf4311a8187b86cafa561b91bec7947a26e51c6  tmp/test1.pgp
24f337938dbad3088722f395bca80d17d2ca672ad0b9181838ad4a09029d0711  tmp/test2.pgp
0 dkg@alice:~$

dkg added a comment.Mar 23 2019, 1:56 AM

(fwiw, all of this testing is done with GnuPG 2.2.14-1, using the package that is in debian/experimental right now; i'd welcome any corroboration with other versions)

werner edited projects, added gnupg (gpg22); removed gnupg.Mar 24 2019, 10:53 AM
werner triaged this task as Normal priority.
werner edited projects, added gnupg (gpg23); removed gnupg (gpg22).May 23 2019, 9:31 AM