blob: c522d54feb484a0236953cf8cb699b1166d9db9f (
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
#!/bin/sh
set -e
unset GREP_OPTIONS
# We don't use a secret keyring, of course, but gpg panics and
# implodes if there isn't one available
SECRETKEYRING="$(mktemp)"
trap "rm -f '${SECRETKEYRING}'" 0 HUP INT QUIT ILL ABRT FPE SEGV PIPE TERM
GPG_CMD="gpg --ignore-time-conflict --no-options --no-default-keyring --secret-keyring ${SECRETKEYRING}"
if [ "$(id -u)" -eq 0 ]; then
# we could use a tmpfile here too, but creation of this tends to be time-consuming
GPG_CMD="$GPG_CMD --trustdb-name /etc/apt/trustdb.gpg"
fi
GPG="$GPG_CMD"
# ubuntu keyrings
MASTER_KEYRING=/usr/share/keyrings/ubuntu-master-keyring.gpg
ARCHIVE_KEYRING=/usr/share/keyrings/ubuntu-archive-keyring.gpg
REMOVED_KEYS=/usr/share/keyrings/ubuntu-archive-removed-keys.gpg
ARCHIVE_KEYRING_URI=http://archive.ubuntu.com/ubuntu/project/ubuntu-archive-keyring.gpg
TMP_KEYRING=/var/lib/apt/keyrings/maybe-import-keyring.gpg
requires_root() {
if [ "$(id -u)" -ne 0 ]; then
echo >&1 "ERROR: This command can only be used by root."
exit 1
fi
}
add_keys_with_verify_against_master_keyring() {
ADD_KEYRING=$1
MASTER=$2
if [ ! -f "$ADD_KEYRING" ]; then
echo "ERROR: '$ADD_KEYRING' not found"
return
fi
if [ ! -f "$MASTER" ]; then
echo "ERROR: '$MASTER' not found"
return
fi
# when adding new keys, make sure that the archive-master-keyring
# is honored. so:
# all keys that are exported must have a valid signature
# from a key in the $distro-master-keyring
add_keys=`$GPG_CMD --keyring $ADD_KEYRING --with-colons --list-keys | grep ^pub | cut -d: -f5`
master_keys=`$GPG_CMD --keyring $MASTER --with-colons --list-keys | grep ^pub | cut -d: -f5`
for add_key in $add_keys; do
# ensure there are no colisions LP: #857472
for master_key in $master_keys; do
if [ "$add_key" = "$master_key" ]; then
echo >&2 "Keyid collision for '$add_key' detected, operation aborted"
return 1
fi
done
# export the add keyring one-by-one
rm -f $TMP_KEYRING
$GPG_CMD --keyring $ADD_KEYRING --export $add_key --output $TMP_KEYRING
# check if signed with the master key and only add in this case
ADDED=0
for master_key in $master_keys; do
if $GPG_CMD --keyring $TMP_KEYRING --check-sigs --with-colons $add_key | grep ^sig | cut -d: -f5 | grep -q $master_key; then
$GPG --import $TMP_KEYRING
ADDED=1
fi
done
if [ $ADDED = 0 ]; then
echo >&2 "Key '$add_key' not added. It is not signed with a master key"
fi
done
rm -f $TMP_KEYRING
}
# update the current archive signing keyring from a network URI
# the archive-keyring keys needs to be signed with the master key
# (otherwise it does not make sense from a security POV)
net_update() {
if [ -z "$ARCHIVE_KEYRING_URI" ]; then
echo >&2 "ERROR: Your distribution is not supported in net-update as no uri for the archive-keyring is set"
exit 1
fi
requires_root
# in theory we would need to depend on wget for this, but this feature
# isn't useable in debian anyway as we have no keyring uri nor a master key
if ! which wget >/dev/null 2>&1; then
echo >&2 "ERROR: an installed wget is required for a network-based update"
exit 1
fi
if [ ! -d /var/lib/apt/keyrings ]; then
mkdir -p /var/lib/apt/keyrings
fi
keyring=/var/lib/apt/keyrings/$(basename $ARCHIVE_KEYRING)
old_mtime=0
if [ -e $keyring ]; then
old_mtime=$(stat -c %Y $keyring)
fi
(cd /var/lib/apt/keyrings; wget --timeout=90 -q -N $ARCHIVE_KEYRING_URI)
if [ ! -e $keyring ]; then
return
fi
new_mtime=$(stat -c %Y $keyring)
if [ $new_mtime -ne $old_mtime ]; then
echo "Checking for new archive signing keys now"
add_keys_with_verify_against_master_keyring $keyring $MASTER_KEYRING
fi
}
update() {
if [ ! -f $ARCHIVE_KEYRING ]; then
echo >&2 "ERROR: Can't find the archive-keyring"
echo >&2 "Is the ubuntu-keyring package installed?"
exit 1
fi
requires_root
# add new keys from the package;
# we do not use add_keys_with_verify_against_master_keyring here,
# because "update" is run on regular package updates. A
# attacker might as well replace the master-archive-keyring file
# in the package and add his own keys. so this check wouldn't
# add any security. we *need* this check on net-update though
$GPG_CMD --quiet --batch --keyring $ARCHIVE_KEYRING --export | $GPG --import
if [ -r "$REMOVED_KEYS" ]; then
# remove no-longer supported/used keys
keys=`$GPG_CMD --keyring $REMOVED_KEYS --with-colons --list-keys | grep ^pub | cut -d: -f5`
for key in $keys; do
if $GPG --list-keys --with-colons | grep ^pub | cut -d: -f5 | grep -q $key; then
$GPG --quiet --batch --delete-key --yes ${key}
fi
done
else
echo "Warning: removed keys keyring $REMOVED_KEYS missing or not readable" >&2
fi
}
usage() {
echo "Usage: apt-key [--keyring file] [command] [arguments]"
echo
echo "Manage apt's list of trusted keys"
echo
echo " apt-key add <file> - add the key contained in <file> ('-' for stdin)"
echo " apt-key del <keyid> - remove the key <keyid>"
echo " apt-key export <keyid> - output the key <keyid>"
echo " apt-key exportall - output all trusted keys"
echo " apt-key update - update keys using the keyring package"
echo " apt-key net-update - update keys using the network"
echo " apt-key list - list keys"
echo " apt-key finger - list fingerprints"
echo " apt-key adv - pass advanced options to gpg (download key)"
echo
echo "If no specific keyring file is given the command applies to all keyring files."
}
# Determine on which keyring we want to work
if [ "$1" = "--keyring" ]; then
#echo "keyfile given"
shift
TRUSTEDFILE="$1"
if [ -r "$TRUSTEDFILE" ]; then
GPG="$GPG --keyring $TRUSTEDFILE --primary-keyring $TRUSTEDFILE"
else
echo >&2 "Error: The specified keyring »$TRUSTEDFILE« is missing or not readable"
exit 1
fi
shift
# otherwise use the default
else
#echo "generate list"
TRUSTEDFILE="/etc/apt/trusted.gpg"
eval $(apt-config shell TRUSTEDFILE Apt::GPGV::TrustedKeyring)
eval $(apt-config shell TRUSTEDFILE Dir::Etc::Trusted/f)
if [ -r "$TRUSTEDFILE" ]; then
GPG="$GPG --keyring $TRUSTEDFILE"
fi
GPG="$GPG --primary-keyring $TRUSTEDFILE"
TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
if [ -d "$TRUSTEDPARTS" ]; then
#echo "parts active"
for trusted in $(run-parts --list $TRUSTEDPARTS --regex '^.*\.gpg$'); do
#echo "part -> $trusted"
GPG="$GPG --keyring $trusted"
done
fi
fi
#echo "COMMAND: $GPG"
command="$1"
if [ -z "$command" ]; then
usage
exit 1
fi
shift
if [ "$command" != "help" ] && ! which gpg >/dev/null 2>&1; then
echo >&2 "Warning: gnupg does not seem to be installed."
echo >&2 "Warning: apt-key requires gnupg for most operations."
echo >&2
fi
case "$command" in
add)
requires_root
$GPG --quiet --batch --import "$1"
echo "OK"
;;
del|rm|remove)
requires_root
$GPG --quiet --batch --delete-key --yes "$1"
echo "OK"
;;
update)
update
;;
net-update)
net_update
;;
list)
$GPG --batch --list-keys
;;
finger*)
$GPG --batch --fingerprint
;;
export)
$GPG --armor --export "$1"
;;
exportall)
$GPG --armor --export
;;
adv*)
echo "Executing: $GPG $*"
$GPG $*
;;
help)
usage
;;
*)
usage
exit 1
;;
esac
|