1# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5from autotest_lib.client.common_lib import utils 6 7AUTHOR = "Chromium OS" 8NAME = "autoupdate_CatchBadSignatures" 9TIME = "MEDIUM" 10TEST_CATEGORY = "Functional" 11TEST_CLASS = "platform" 12TEST_TYPE = "server" 13JOB_RETRIES = 2 14# TODO(jorgelo): move this to bvt-cq after crbug.com/427384 is fixed. 15ATTRIBUTES = "suite:au-perbuild" 16BUG_TEMPLATE = { 17 'cc': ['chromeos-installer-alerts@google.com'], 18 'components': ['Internals>Installer'], 19} 20 21DOC = """ 22This is a test to verify that update_engine correctly checks signatures in the 23metadata hash and the update payload itself. This is achieved by feeding updates 24to update_engine where the private key used to make the signature, intentionally 25does not match with the public key used for verification. 26 27By its very nature, this test requires an image signed with a well-known 28key. Since payload-generation is a resource-intensive process, we prepare the 29image ahead of time. Also, since the image is never successfully applied, we can 30get away with not caring that the image is built for one board but used on 31another. 32 33If you ever need to replace the test image and payloads, follow these simple 34(jk!) steps: 35 36 1. Build a test image: 37 38 $ cd ~/trunk/src/scripts 39 $ ./build_packages --board=${BOARD} 40 $ ./build_image --board=${BOARD} --noenable_rootfs_verification test 41 42 Alternatively, you can use any kind of Chrome OS image you already have or 43 downloaded. 44 45 2. Reduce the size of Rootfs and Kernel partitions. This is done so these 46 autotests don't have to download a huge payload as the payload is not going 47 to be applied fully anyway. This can be done many ways. One is: 48 49 $ sudo losetup -fP chromiumos_test_image.bin 50 51 At this point take a note of which loopback device was set up for the 52 image. e.g. /dev/loop1 53 54 $ sudo mkfs.ext4 -b 4k /dev/loop1p3 100 # For ROOT-A 55 $ sudo mkfs.ext4 -b 4k /dev/loop1p4 100 # For KERN-B 56 $ mkdir rootfs kernel 57 $ sudo mount /dev/loop1p3 rootfs 58 $ sudo mount /dev/loop1p4 kernel 59 60 Now you need a lsb-release file copied from any Chrome OS. 61 62 $ mkdir rootfs/etc && touch cp <lsb-release> rootfs/etc 63 $ touch kernel/fake-kernel.bin # Optional 64 $ sudo umount rootfs kernel 65 66 Now, the chromiumos_test_image.bin has very small Rootfs and Kernel 67 partitions. 68 69 3. Generate a full payload in which its metadata and payload signatures are 70 signed by two different private keys. An update payload has two signatures 71 embedded in it. The first is the signature of the header (metadata 72 signature) and the second is the signature of the entire payload (payload 73 signature). We do two tests here: One that makes sure the metadata 74 signature verification fails if signed incorrectly (we do this by sending a 75 different public key that doesn't verify the aforementioned signature). The 76 second one to make sure the metadata signature verification passes fine, 77 but the payload signature verification fails. One (not so) simple, but 78 available way of doing this is as follows: 79 80 Since we can't generate a payload with metadata and payload signatures 81 signed by different keys (simply we haven't designed tools for that), we 82 need to sign a payload two times with different keys and swap the payload 83 signature of one of them with the other. 84 85 $ mkdir key1 key2 86 $ cros_generate_update_payload \ 87 --image chromiumos_test_image.bin \ 88 --output key1/full.bin \ 89 --work_dir key1 \ 90 --private_key ~/trunk/src/aosp/system/update_engine/unittest_key.pem 91 $ cros_generate_update_payload \ 92 --image chromiumos_test_image.bin \ 93 --output key2/full.bin \ 94 --work_dir key2 \ 95 --private_key ~/trunk/src/aosp/system/update_engine/unittest_key2.pem 96 97 Now we should re-sign an unsigned image (key1/delta.bin) with metadata 98 signature from key1 and payload signature from key2 directories. Because we 99 passed the --work_dir flag, the intermediate temporary files (including 100 signature files) are saved in those directories. 101 102 $ delta_generator \ 103 --in_file=key1/delta.bin \ 104 --metadata_signature_file=key1/signature_metadata_<hash>.bin \ 105 --payload_signature_file=key2/signature_payload_<hash>.bin \ 106 --out_file=autoupdate_CatchBadSignatures.bin 107 108 This file is signed and ready to be tested. 109 110 4. Generate/modify a payload properties file. For each payload we need a 111 payload properties file in JSON format. This file has already been 112 generated in the previous step when we generated the signed image. We just 113 need to modify it. 114 115 $ cp key1/delta.bin.json autoupdate_CatchBadSignatures.bin.json 116 117 However, since we re-signed the payload, we need to calculate its SHA256 118 hash again. Easy way to do this is to use either delta_generator or 119 cros_generate_update_payload as: 120 121 $ cros_generate_update_payload \ 122 --payload autoupdate_CatchBadSignatures.bin --output foo.json 123 124 Open autoupdate_CatchBadSignatures.bin.json and replace the value of 125 sha256_hex with the one from foo.json. Also empty the value of 'appid' 126 (keep its key) to empty string. 127 128 5. Replace _IMAGE_PUBLIC_KEY2 in this file with value in 129 key2/full.bin.json. (You don't need to do this step if you used the same 130 keys as mentioned above.) 131 132 6. Upload the generated payload and its properties file to the public 133 gsbucket. 134 135 7. Now run the test and ensure that it passes. 136 137 $ cd ~/trunk/src/scripts 138 $ test_that -b ${BOARD} --fast <DUT_IP> autoupdate_CatchBadSignatures 139 140With this in place, you can now run the test: 141 142 $ test_that <DUT_IP> autoupdate_CatchBadSignatures -b ${BOARD} 143 144""" 145 146def run_test(machine): 147 """Execute a test configuration on a given machine.""" 148 host = hosts.create_host(machine) 149 job.run_test("autoupdate_CatchBadSignatures", host=host) 150 151# Invoke parallel tests. 152parallel_simple(run_test, machines) 153