summaryrefslogtreecommitdiff
path: root/cmdline/apt-key
blob: b579e5a53c94aeae1928bfeecba103f9729445ef (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
#!/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

GPG_CMD="gpg --ignore-time-conflict --no-options --no-default-keyring --secret-keyring /etc/apt/secring.gpg --trustdb-name /etc/apt/trustdb.gpg"
GPG="$GPG_CMD --keyring /etc/apt/trusted.gpg"


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

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
	ADDED=0
	for master_key in $master_keys; do
	    if $GPG_CMD --keyring $ADD_KEYRING --list-sigs --with-colons $add_key | grep ^sig | cut -d: -f5 | grep -q $master_key; then
		$GPG_CMD --quiet --batch --keyring $ADD_KEYRING --export $add_key | $GPG --import
		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
}

# 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 "ERROR: no location for the archive-keyring given" 
    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 -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

    # add new keys from the package;

    # we do not use add_keys_with_verify_against_master_keyring here,
    # because we "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 [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
}

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)
        $GPG --quiet --batch --import "$1"
        echo "OK"
        ;;
    del|rm|remove)
        $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