You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.8 KiB
148 lines
5.8 KiB
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
from autotest_lib.client.common_lib import utils
|
|
|
|
AUTHOR = "Chromium OS"
|
|
NAME = "autoupdate_CatchBadSignatures"
|
|
TIME = "MEDIUM"
|
|
TEST_CATEGORY = "Functional"
|
|
TEST_CLASS = "platform"
|
|
TEST_TYPE = "server"
|
|
ATTRIBUTES = "suite:bvt-inline"
|
|
JOB_RETRIES = 2
|
|
|
|
DOC = """
|
|
This is a test to verify that update_engine correctly checks signatures in the
|
|
metadata hash and the update payload itself. This is achieved by feeding updates
|
|
to update_engine where the private key used to make the signature, intentionally
|
|
does not match with the public key used for verification.
|
|
|
|
By its very nature, this test requires an image signed with a well-known
|
|
key. Since payload-generation is a resource-intensive process, we prepare the
|
|
image ahead of time. Also, since the image is never successfully applied, we can
|
|
get away with not caring that the image is built for one board but used on
|
|
another.
|
|
|
|
If you ever need to replace the test image and payloads, follow these simple
|
|
(jk!) steps:
|
|
|
|
1. Build a test image:
|
|
|
|
$ cd ~/trunk/src/scripts
|
|
$ ./build_packages --board=${BOARD}
|
|
$ ./build_image --board=${BOARD} --noenable_rootfs_verification test
|
|
|
|
Alternatively, you can use any kind of Chrome OS image you already have or
|
|
downloaded.
|
|
|
|
2. Reduce the size of Rootfs and Kernel partitions. This is done so these
|
|
autotests don't have to download a huge payload as the payload is not going
|
|
to be applied fully anyway. This can be done many ways. One is:
|
|
|
|
$ sudo losetup -fP chromiumos_test_image.bin
|
|
|
|
At this point take a note of which loopback device was set up for the
|
|
image. e.g. /dev/loop1
|
|
|
|
$ sudo mkfs.ext4 -b 4k /dev/loop1p3 100 # For ROOT-A
|
|
$ sudo mkfs.ext4 -b 4k /dev/loop1p4 100 # For KERN-B
|
|
$ mkdir rootfs kernel
|
|
$ sudo mount /dev/loop1p3 rootfs
|
|
$ sudo mount /dev/loop1p4 kernel
|
|
|
|
Now you need a lsb-release file copied from any Chrome OS.
|
|
|
|
$ mkdir rootfs/etc && touch cp <lsb-release> rootfs/etc
|
|
$ touch kernel/fake-kernel.bin # Optional
|
|
$ sudo umount rootfs kernel
|
|
|
|
Now, the chromiumos_test_image.bin has very small Rootfs and Kernel
|
|
partitions.
|
|
|
|
3. Generate a full payload in which its metadata and payload signatures are
|
|
signed by two different private keys. An update payload has two signatures
|
|
embedded in it. The first is the signature of the header (metadata
|
|
signature) and the second is the signature of the entire payload (payload
|
|
signature). We do two tests here: One that makes sure the metadata
|
|
signature verification fails if signed incorrectly (we do this by sending a
|
|
different public key that doesn't verify the aforementioned signature). The
|
|
second one to make sure the metadata signature verification passes fine,
|
|
but the payload signature verification fails. One (not so) simple, but
|
|
available way of doing this is as follows:
|
|
|
|
Since we can't generate a payload with metadata and payload signatures
|
|
signed by different keys (simply we haven't designed tools for that), we
|
|
need to sign a payload two times with different keys and swap the payload
|
|
signature of one of them with the other.
|
|
|
|
$ mkdir key1 key2
|
|
$ cros_generate_update_payload \
|
|
--image chromiumos_test_image.bin \
|
|
--output key1/full.bin \
|
|
--work_dir key1 \
|
|
--private_key ~/trunk/src/aosp/system/update_engine/unittest_key.pem
|
|
$ cros_generate_update_payload \
|
|
--image chromiumos_test_image.bin \
|
|
--output key2/full.bin \
|
|
--work_dir key2 \
|
|
--private_key ~/trunk/src/aosp/system/update_engine/unittest_key2.pem
|
|
|
|
Now we should re-sign an unsigned image (key1/delta.bin) with metadata
|
|
signature from key1 and payload signature from key2 directories. Because we
|
|
passed the --work_dir flag, the intermediate temporary files (including
|
|
signature files) are saved in those directories.
|
|
|
|
$ delta_generator \
|
|
--in_file=key1/delta.bin \
|
|
--metadata_signature_file=key1/signature_metadata_<hash>.bin \
|
|
--payload_signature_file=key2/signature_payload_<hash>.bin \
|
|
--out_file=autoupdate_CatchBadSignatures.bin
|
|
|
|
This file is signed and ready to be tested.
|
|
|
|
4. Generate/modify a payload properties file. For each payload we need a
|
|
payload properties file in JSON format. This file has already been
|
|
generated in the previous step when we generated the signed image. We just
|
|
need to modify it.
|
|
|
|
$ cp key1/delta.bin.json autoupdate_CatchBadSignatures.bin.json
|
|
|
|
However, since we re-signed the payload, we need to calculate its SHA256
|
|
hash again. Easy way to do this is to use either delta_generator or
|
|
cros_generate_update_payload as:
|
|
|
|
$ cros_generate_update_payload \
|
|
--payload autoupdate_CatchBadSignatures.bin --output foo.json
|
|
|
|
Open autoupdate_CatchBadSignatures.bin.json and replace the value of
|
|
sha256_hex with the one from foo.json. Also empty the value of 'appid'
|
|
(keep its key) to empty string.
|
|
|
|
5. Replace _IMAGE_PUBLIC_KEY2 in this file with value in
|
|
key2/full.bin.json. (You don't need to do this step if you used the same
|
|
keys as mentioned above.)
|
|
|
|
6. Upload the generated payload and its properties file to the public
|
|
gsbucket.
|
|
|
|
7. Now run the test and ensure that it passes.
|
|
|
|
$ cd ~/trunk/src/scripts
|
|
$ test_that -b ${BOARD} --fast <DUT_IP> autoupdate_CatchBadSignatures
|
|
|
|
With this in place, you can now run the test:
|
|
|
|
$ test_that <DUT_IP> autoupdate_CatchBadSignatures -b ${BOARD}
|
|
|
|
"""
|
|
|
|
def run_test(machine):
|
|
"""Execute a test configuration on a given machine."""
|
|
host = hosts.create_host(machine)
|
|
job.run_test("autoupdate_CatchBadSignatures", host=host)
|
|
|
|
# Invoke parallel tests.
|
|
parallel_simple(run_test, machines)
|