blob: bd614324e78e23a03d1551e9c3b96d0a021064d5 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#!/bin/bash
# Copyright (c) 2012 Jonathan McDowell <noodles@earth.li>,
# 2019 Daniel Kahn Gillmor <dkg@fifthhorseman.net>
# GNU GPL; v2 or later
# Given a key directory, prune, clean, or minimize the keys
# "prune" just does basic cleanup on the file, without getting rid of
# any third-party signatures.
set -e
if [ -z "$1" ] || [ -z "$2" ]; then
cat >&2 <<EOF
Usage: $0 [prune|launder|clean|minimal] dir
prune: remove invalid parts
launder: invoke GnuPG's merge logic to trim the key
clean: prune and drop non-debian third-party certifications
minimal: prune and remove *all* third-party certifications
EOF
exit 1
fi
declare -a GPGOPTIONS=(--batch
--no-tty
--quiet
--no-options
--homedir=/dev/null
--trust-model=always
--fixed-list-mode
--with-colons
--export-options=no-export-attributes
)
if [ "$1" == prune ]; then
GPGOPTIONS+=(--no-keyring
--import-options=import-export
)
elif [ "$1" == launder ]; then
# we are going to do something very ugly...
# see https://dev.gnupg.org/T4421
: pass
elif [ "$1" == clean ]; then
# we need to include all the known keys so that we keep the
# interlocking signatures
make
GPGOPTIONS+=(--no-default-keyring
--import-options=import-export,import-clean
--export-options=export-clean
--keyring "$(readlink -f output/keyrings/debian-keyring.gpg)"
--keyring "$(readlink -f output/keyrings/debian-nonupload.gpg)"
--keyring "$(readlink -f output/keyrings/debian-maintainers.gpg)"
--keyring "$(readlink -f output/keyrings/debian-role-keys.gpg)"
--keyring "$(readlink -f output/keyrings/emeritus-keyring.gpg)"
)
elif [ "$1" == minimal ]; then
GPGOPTIONS+=(--no-keyring
--import-options=import-export,import-minimal
--export-options=export-minimal
)
else
echo "Must specify prune, launder, clean or minimal; not $1" >&2
exit 1
fi
if [ ! -d "$2" ]; then
printf '%s is not a directory' "$2" >&2
exit 1
fi
# 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
export-options no-export-attributes
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")" &&
[ -n "$fpr" ] &&
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
else
printf 'Merging failed for %s (fpr: %s)\n' "$key" "$fpr" >&2
fi
else
printf 'Could not find minimal TPK for %s (fpr: %s)\n' "$key" "$fpr" >&2
fi
else
printf 'failed to do initial import of %s\n' "$key" >&2
fi
rm -rf "$interim"
[ $success = true ]
}
cd "$2"
for key in 0x*; do
success=false
if [ "$1" == launder ]; then
if launder_tpk "$key" "$key.new"; then
success=true
fi
else
if gpg "${GPGOPTIONS[@]}" --output "$key.new" --import "$key"; then
success=true
fi
fi
if [ $success = true ] && [ -s $key.new ]; then
OLDSIZE=$(stat -c "%s" "$key")
NEWSIZE=$(stat -c "%s" "$key.new")
if [ $OLDSIZE -gt $NEWSIZE ]; then
echo "Cleaning $key [$OLDSIZE] -> [$NEWSIZE]"
mv "$key.new" "$key"
elif [ $OLDSIZE -eq $NEWSIZE ] && ! cmp --quiet "$key" "$key.new" ; then
printf "Packets were reordered in $key"
if [ "$1" == launder ]; then
echo " (but ignoring while doing launder: https://dev.gnupg.org/T4422)"
else
mv "$key.new" "$key"
echo
fi
fi
fi
[ -e "$key.new" ] && rm "$key.new"
done
exit 0
|