summaryrefslogtreecommitdiffstats
path: root/test/integration/test-apt-update-nofallback
blob: d7e30ba207fe20ac087cb0947244fc6d10268f58 (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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#!/bin/sh
#
# ensure we never fallback from a signed to a unsigned repo
# 
# hash checks are done in 
# 
set -e

simulate_mitm_and_inject_evil_package()
{
    redatereleasefiles '+1 hour'
    rm -f "$APTARCHIVE/dists/unstable/InRelease" "$APTARCHIVE/dists/unstable/Release.gpg"
    inject_evil_package
}

inject_evil_package()
{
    cat > "$APTARCHIVE/dists/unstable/main/binary-i386/Packages" <<EOF
Package: evil
Installed-Size: 29
Maintainer: Joe Sixpack <joe@example.org>
Architecture: all
Version: 1.0
Filename: pool/evil_1.0_all.deb
Size: 1270
Description: an autogenerated evil package
EOF
    # avoid ims hit
    touch -d '+1hour' aptarchive/dists/unstable/main/binary-i386/Packages
    compressfile aptarchive/dists/unstable/main/binary-i386/Packages
}

assert_update_is_refused_and_last_good_state_used()
{
    testfailuremsg "E: The repository 'file:${APTARCHIVE} unstable Release' is no longer signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details." aptget update

    assert_repo_is_intact
}

assert_repo_is_intact()
{
    testsuccessequal "dpkg/now 1.16.2+fake all [installed,local]
foo/unstable 2.0 all" apt list -qq
    testsuccess aptget install -y -s foo
    testfailure aptget install -y evil
    testsuccess aptget source foo --print-uris

    LISTDIR=rootdir/var/lib/apt/lists
    testempty find "$LISTDIR" -name 'InRelease' -o -name 'Release.gpg'
}

setupaptarchive_with_lists_clean()
{
    setupaptarchive --no-update
    rm -rf rootdir/var/lib/apt/lists
}

test_from_inrelease_to_unsigned()
{
    export APT_DONT_SIGN='Release.gpg'
    setupaptarchive_with_lists_clean
    testsuccess aptget update
    listcurrentlistsdirectory > lists.before

    simulate_mitm_and_inject_evil_package
    assert_update_is_refused_and_last_good_state_used
    testfileequal lists.before "$(listcurrentlistsdirectory)"
}

test_from_release_gpg_to_unsigned()
{
    export APT_DONT_SIGN='InRelease'
    setupaptarchive_with_lists_clean
    testsuccess aptget update
    listcurrentlistsdirectory > lists.before

    simulate_mitm_and_inject_evil_package
    assert_update_is_refused_and_last_good_state_used
    testfileequal lists.before "$(listcurrentlistsdirectory)"
}

test_from_inrelease_to_unsigned_with_override()
{
    export APT_DONT_SIGN='Release.gpg'
    # setup archive with InRelease file
    setupaptarchive_with_lists_clean
    testsuccess aptget update

    # simulate moving to a unsigned but otherwise valid repo
    simulate_mitm_and_inject_evil_package
    generatereleasefiles '+2 hours'
    find "$APTARCHIVE" -name '*Packages*' -exec touch -d '+2 hours' {} \;

    # and ensure we can update to it (with enough force) 
    testfailure apt update
    testfailure aptget update
    testfailure aptget update --allow-insecure-repositories
    testfailure aptget update --no-allow-insecure-repositories
    sed -i 's#^deb\(-src\)\? #deb\1 [allow-downgrade-to-insecure=yes] #' rootdir/etc/apt/sources.list.d/*
    testfailure aptget update --no-allow-insecure-repositories
    testfailure apt update
    testwarning apt update --allow-insecure-repositories \
        -o Debug::pkgAcquire::Worker=1 -o Debug::pkgAcquire::Auth=1
    sed -i 's#^deb\(-src\)\? \[allow-downgrade-to-insecure=yes\] #deb\1 #' rootdir/etc/apt/sources.list.d/*
    # but that the individual packages are still considered untrusted
    testfailureequal "WARNING: The following packages cannot be authenticated!
  evil
E: There were unauthenticated packages and -y was used without --allow-unauthenticated" aptget install -qq -y evil
}

test_from_inrelease_to_norelease_with_override()
{
    # setup archive with InRelease file
    setupaptarchive_with_lists_clean
    testsuccess aptget update

    # simulate moving to a unsigned but otherwise valid repo
    simulate_mitm_and_inject_evil_package
    find "$APTARCHIVE" -name '*Release*' -delete
    find "$APTARCHIVE" -name '*Packages*' -exec touch -d '+2 hours' {} \;

    # and ensure we can update to it (with enough force) 
    testfailure aptget update
    testfailure aptget update --allow-insecure-repositories
    testwarning aptget update --allow-insecure-repositories \
        -o Acquire::AllowDowngradeToInsecureRepositories=1 -o Debug::pkgAcquire::Worker=1 -o Debug::pkgAcquire::Auth=1
    # but that the individual packages are still considered untrusted
    testfailureequal "WARNING: The following packages cannot be authenticated!
  evil
E: There were unauthenticated packages and -y was used without --allow-unauthenticated" aptget install -qq -y evil
}

test_cve_2012_0214()
{
    # see https://bugs.launchpad.net/ubuntu/+source/apt/+bug/947108
    #
    # it was possible to MITM the download so that InRelease/Release.gpg
    # are not delivered (404) and a altered Release file was send
    #
    # apt left the old InRelease file in /var/lib/apt/lists and downloaded
    # the unauthenticated Release file too giving the false impression that
    # Release was authenticated
    #
    # Note that this is pretty much impossible nowadays because:
    # a) InRelease is left as is, not split to InRelease/Release as it was 
    #    in the old days
    # b) we refuse to go from signed->unsigned
    #
    # Still worth having a regression test the simulates the condition

    export APT_DONT_SIGN='Release.gpg'
    setupaptarchive_with_lists_clean
    testsuccess aptget update
    listcurrentlistsdirectory > lists.before

    # do what CVE-2012-0214 did
    rm -f "$APTARCHIVE/dists/unstable/InRelease" "$APTARCHIVE/dists/unstable/Release.gpg"
    inject_evil_package
    # build valid Release file
    aptftparchive -qq release ./aptarchive > aptarchive/dists/unstable/Release

    assert_update_is_refused_and_last_good_state_used
    testfileequal lists.before "$(listcurrentlistsdirectory)"

    # ensure there is no _Release file downloaded
    testfailure ls rootdir/var/lib/apt/lists/*_Release
}

test_subvert_inrelease()
{
    export APT_DONT_SIGN='Release.gpg'
    setupaptarchive_with_lists_clean
    testsuccess aptget update
    listcurrentlistsdirectory > lists.before

    # replace InRelease with something else
    mv "$APTARCHIVE/dists/unstable/Release" "$APTARCHIVE/dists/unstable/InRelease"

    testfailuremsg "E: Failed to fetch file://${APTARCHIVE}/dists/unstable/InRelease  Clearsigned file isn't valid, got 'NOSPLIT' (does the network require authentication?)
E: The repository 'file:${APTARCHIVE} unstable InRelease' is no longer signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details." aptget update

    # ensure we keep the repo
    testfileequal lists.before "$(listcurrentlistsdirectory)"
    assert_repo_is_intact
}

test_inrelease_to_invalid_inrelease()
{
    export APT_DONT_SIGN='Release.gpg'
    setupaptarchive_with_lists_clean
    testsuccess aptget update
    listcurrentlistsdirectory > lists.before

    # now remove InRelease and subvert Release do no longer verify
    sed -i 's/^Codename:.*/Codename: evil!/' "$APTARCHIVE/dists/unstable/InRelease"
    inject_evil_package

    testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable InRelease: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Failed to fetch file:${APTARCHIVE}/dists/unstable/InRelease  The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq

    # ensure we keep the repo
    testfailure grep 'evil' rootdir/var/lib/apt/lists/*InRelease
    testfileequal lists.before "$(listcurrentlistsdirectory)"
    assert_repo_is_intact
}

test_release_gpg_to_invalid_release_release_gpg()
{
    export APT_DONT_SIGN='InRelease'
    setupaptarchive_with_lists_clean
    testsuccess aptget update
    listcurrentlistsdirectory > lists.before

    # now subvert Release do no longer verify
    echo "Some evil data" >> "$APTARCHIVE/dists/unstable/Release"
    inject_evil_package

    testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file:${APTARCHIVE} unstable Release: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Failed to fetch file:${APTARCHIVE}/dists/unstable/Release.gpg  The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -qq

    testfailure grep 'evil' rootdir/var/lib/apt/lists/*Release
    testfileequal lists.before "$(listcurrentlistsdirectory)"
    assert_repo_is_intact
}


TESTDIR="$(readlink -f "$(dirname "$0")")"
. "$TESTDIR/framework"

setupenvironment
configarchitecture "i386"

# a "normal" package with source and binary
buildsimplenativepackage 'foo' 'all' '2.0'

# setup the archive and ensure we have a single package that installs fine
setupaptarchive
APTARCHIVE="$(readlink -f ./aptarchive)"
assert_repo_is_intact

# test the various cases where a repo may go from signed->unsigned
msgmsg "test_from_inrelease_to_unsigned"
test_from_inrelease_to_unsigned

msgmsg "test_from_release_gpg_to_unsigned"
test_from_release_gpg_to_unsigned

# ensure we do not regress on CVE-2012-0214
msgmsg "test_cve_2012_0214"
test_cve_2012_0214

# ensure InRelease can not be subverted
msgmsg "test_subvert_inrelease"
test_subvert_inrelease

# ensure we revert to last good state if InRelease does not verify
msgmsg "test_inrelease_to_invalid_inrelease"
test_inrelease_to_invalid_inrelease

# ensure we revert to last good state if Release/Release.gpg does not verify
msgmsg "test_release_gpg_to_invalid_release_release_gpg"
test_release_gpg_to_invalid_release_release_gpg

# ensure we can override the downgrade error
msgmsg "test_from_inrelease_to_unsigned_with_override"
test_from_inrelease_to_unsigned_with_override
msgmsg "test_from_inrelease_to_norelease_with_override"
test_from_inrelease_to_norelease_with_override