Exemple #1
0
 def test_GetAvbChainedPartitionArg_withPrivateKey(self):
   key = os.path.join(self.testdata_dir, 'testkey.key')
   info_dict = {
       'avb_avbtool': 'avbtool',
       'avb_product_key_path': key,
       'avb_product_rollback_index_location': 2,
   }
   args = common.GetAvbChainedPartitionArg('product', info_dict).split(':')
   self.assertEqual(3, len(args))
   self.assertEqual('product', args[0])
   self.assertEqual('2', args[1])
   self.assertTrue(os.path.exists(args[2]))
Exemple #2
0
 def test_GetAvbChainedPartitionArg(self):
   pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
   info_dict = {
       'avb_avbtool': 'avbtool',
       'avb_system_key_path': pubkey,
       'avb_system_rollback_index_location': 2,
   }
   args = common.GetAvbChainedPartitionArg('system', info_dict).split(':')
   self.assertEqual(3, len(args))
   self.assertEqual('system', args[0])
   self.assertEqual('2', args[1])
   self.assertTrue(os.path.exists(args[2]))
Exemple #3
0
def AppendVBMetaArgsForPartition(cmd, partition, image):
    """Appends the VBMeta arguments for partition.

  It sets up the VBMeta argument by including the partition descriptor from the
  given 'image', or by configuring the partition as a chained partition.

  Args:
    cmd: A list of command args that will be used to generate the vbmeta image.
        The argument for the partition will be appended to the list.
    partition: The name of the partition (e.g. "system").
    image: The path to the partition image.
  """
    # Check if chain partition is used.
    key_path = OPTIONS.info_dict.get("avb_" + partition + "_key_path")
    if key_path:
        chained_partition_arg = common.GetAvbChainedPartitionArg(
            partition, OPTIONS.info_dict)
        cmd.extend(["--chain_partition", chained_partition_arg])
    else:
        cmd.extend(["--include_descriptors_from_image", image])
def ValidateVerifiedBootImages(input_tmp, info_dict, options):
    """Validates the Verified Boot related images.

  For Verified Boot 1.0, it verifies the signatures of the bootable images
  (boot/recovery etc), as well as the dm-verity metadata in system images
  (system/vendor/product). For Verified Boot 2.0, it calls avbtool to verify
  vbmeta.img, which in turn verifies all the descriptors listed in vbmeta.

  Args:
    input_tmp: The top-level directory of unpacked target-files.zip.
    info_dict: The loaded info dict.
    options: A dict that contains the user-supplied public keys to be used for
        image verification. In particular, 'verity_key' is used to verify the
        bootable images in VB 1.0, and the vbmeta image in VB 2.0, where
        applicable. 'verity_key_mincrypt' will be used to verify the system
        images in VB 1.0.

  Raises:
    AssertionError: On any verification failure.
  """
    # Verified boot 1.0 (images signed with boot_signer and verity_signer).
    if info_dict.get('boot_signer') == 'true':
        logging.info('Verifying Verified Boot images...')

        # Verify the boot/recovery images (signed with boot_signer), against the
        # given X.509 encoded pubkey (or falling back to the one in the info_dict if
        # none given).
        verity_key = options['verity_key']
        if verity_key is None:
            verity_key = info_dict['verity_key'] + '.x509.pem'
        for image in ('boot.img', 'recovery.img', 'recovery-two-step.img'):
            if image == 'recovery-two-step.img':
                image_path = os.path.join(input_tmp, 'OTA', image)
            else:
                image_path = os.path.join(input_tmp, 'IMAGES', image)
            if not os.path.exists(image_path):
                continue

            cmd = [
                'boot_signer', '-verify', image_path, '-certificate',
                verity_key
            ]
            proc = common.Run(cmd)
            stdoutdata, _ = proc.communicate()
            assert proc.returncode == 0, \
                'Failed to verify {} with boot_signer:\n{}'.format(image, stdoutdata)
            logging.info('Verified %s with boot_signer (key: %s):\n%s', image,
                         verity_key, stdoutdata.rstrip())

    # Verify verity signed system images in Verified Boot 1.0. Note that not using
    # 'elif' here, since 'boot_signer' and 'verity' are not bundled in VB 1.0.
    if info_dict.get('verity') == 'true':
        # First verify that the verity key is built into the root image (regardless
        # of system-as-root).
        verity_key_mincrypt = os.path.join(input_tmp, 'ROOT', 'verity_key')
        assert os.path.exists(verity_key_mincrypt), 'Missing verity_key'

        # Verify /verity_key matches the one given via command line, if any.
        if options['verity_key_mincrypt'] is None:
            logging.warn(
                'Skipped checking the content of /verity_key, as the key file not '
                'provided. Use --verity_key_mincrypt to specify.')
        else:
            expected_key = options['verity_key_mincrypt']
            assert filecmp.cmp(expected_key, verity_key_mincrypt, shallow=False), \
                "Mismatching mincrypt verity key files"
            logging.info('Verified the content of /verity_key')

        # For devices with a separate ramdisk (i.e. non-system-as-root), there must
        # be a copy in ramdisk.
        if info_dict.get("system_root_image") != "true":
            verity_key_ramdisk = os.path.join(input_tmp, 'BOOT', 'RAMDISK',
                                              'verity_key')
            assert os.path.exists(
                verity_key_ramdisk), 'Missing verity_key in ramdisk'

            assert filecmp.cmp(
                verity_key_mincrypt, verity_key_ramdisk, shallow=False), \
                    'Mismatching verity_key files in root and ramdisk'
            logging.info('Verified the content of /verity_key in ramdisk')

        # Then verify the verity signed system/vendor/product images, against the
        # verity pubkey in mincrypt format.
        for image in ('system.img', 'vendor.img', 'product.img'):
            image_path = os.path.join(input_tmp, 'IMAGES', image)

            # We are not checking if the image is actually enabled via info_dict (e.g.
            # 'system_verity_block_device=...'). Because it's most likely a bug that
            # skips signing some of the images in signed target-files.zip, while
            # having the top-level verity flag enabled.
            if not os.path.exists(image_path):
                continue

            cmd = [
                'verity_verifier', image_path, '-mincrypt', verity_key_mincrypt
            ]
            proc = common.Run(cmd)
            stdoutdata, _ = proc.communicate()
            assert proc.returncode == 0, \
                'Failed to verify {} with verity_verifier (key: {}):\n{}'.format(
                    image, verity_key_mincrypt, stdoutdata)
            logging.info('Verified %s with verity_verifier (key: %s):\n%s',
                         image, verity_key_mincrypt, stdoutdata.rstrip())

    # Handle the case of Verified Boot 2.0 (AVB).
    if info_dict.get("avb_enable") == "true":
        logging.info('Verifying Verified Boot 2.0 (AVB) images...')

        key = options['verity_key']
        if key is None:
            key = info_dict['avb_vbmeta_key_path']

        # avbtool verifies all the images that have descriptors listed in vbmeta.
        image = os.path.join(input_tmp, 'IMAGES', 'vbmeta.img')
        cmd = [
            info_dict['avb_avbtool'], 'verify_image', '--image', image,
            '--key', key
        ]

        # Append the args for chained partitions if any.
        for partition in common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS:
            key_name = 'avb_' + partition + '_key_path'
            if info_dict.get(key_name) is not None:
                # Use the key file from command line if specified; otherwise fall back
                # to the one in info dict.
                key_file = options.get(key_name, info_dict[key_name])
                chained_partition_arg = common.GetAvbChainedPartitionArg(
                    partition, info_dict, key_file)
                cmd.extend(
                    ["--expected_chain_partition", chained_partition_arg])

        proc = common.Run(cmd)
        stdoutdata, _ = proc.communicate()
        assert proc.returncode == 0, \
            'Failed to verify {} with avbtool (key: {}):\n{}'.format(
                image, key, stdoutdata)

        logging.info('Verified %s with avbtool (key: %s):\n%s', image, key,
                     stdoutdata.rstrip())
Exemple #5
0
def ValidateVerifiedBootImages(input_tmp, info_dict, options):
    """Validates the Verified Boot related images.

  For Verified Boot 1.0, it verifies the signatures of the bootable images
  (boot/recovery etc), as well as the dm-verity metadata in system images
  (system/vendor/product). For Verified Boot 2.0, it calls avbtool to verify
  vbmeta.img, which in turn verifies all the descriptors listed in vbmeta.

  Args:
    input_tmp: The top-level directory of unpacked target-files.zip.
    info_dict: The loaded info dict.
    options: A dict that contains the user-supplied public keys to be used for
        image verification. In particular, 'verity_key' is used to verify the
        bootable images in VB 1.0, and the vbmeta image in VB 2.0, where
        applicable. 'verity_key_mincrypt' will be used to verify the system
        images in VB 1.0.

  Raises:
    AssertionError: On any verification failure.
  """
    # See bug 159299583
    # After commit 5277d1015, some images (e.g. acpio.img and tos.img) are no
    # longer copied from RADIO to the IMAGES folder. But avbtool assumes that
    # images are in IMAGES folder. So we symlink them.
    symlinkIfNotExists(os.path.join(input_tmp, "RADIO"),
                       os.path.join(input_tmp, "IMAGES"))
    # Verified boot 1.0 (images signed with boot_signer and verity_signer).
    if info_dict.get('boot_signer') == 'true':
        logging.info('Verifying Verified Boot images...')

        # Verify the boot/recovery images (signed with boot_signer), against the
        # given X.509 encoded pubkey (or falling back to the one in the info_dict if
        # none given).
        verity_key = options['verity_key']
        if verity_key is None:
            verity_key = info_dict['verity_key'] + '.x509.pem'
        for image in ('boot.img', 'recovery.img', 'recovery-two-step.img'):
            if image == 'recovery-two-step.img':
                image_path = os.path.join(input_tmp, 'OTA', image)
            else:
                image_path = os.path.join(input_tmp, 'IMAGES', image)
            if not os.path.exists(image_path):
                continue

            cmd = [
                'boot_signer', '-verify', image_path, '-certificate',
                verity_key
            ]
            proc = common.Run(cmd)
            stdoutdata, _ = proc.communicate()
            assert proc.returncode == 0, \
                'Failed to verify {} with boot_signer:\n{}'.format(image, stdoutdata)
            logging.info('Verified %s with boot_signer (key: %s):\n%s', image,
                         verity_key, stdoutdata.rstrip())

    # Verify verity signed system images in Verified Boot 1.0. Note that not using
    # 'elif' here, since 'boot_signer' and 'verity' are not bundled in VB 1.0.
    if info_dict.get('verity') == 'true':
        # First verify that the verity key is built into the root image (regardless
        # of system-as-root).
        verity_key_mincrypt = os.path.join(input_tmp, 'ROOT', 'verity_key')
        assert os.path.exists(verity_key_mincrypt), 'Missing verity_key'

        # Verify /verity_key matches the one given via command line, if any.
        if options['verity_key_mincrypt'] is None:
            logging.warn(
                'Skipped checking the content of /verity_key, as the key file not '
                'provided. Use --verity_key_mincrypt to specify.')
        else:
            expected_key = options['verity_key_mincrypt']
            assert filecmp.cmp(expected_key, verity_key_mincrypt, shallow=False), \
                "Mismatching mincrypt verity key files"
            logging.info('Verified the content of /verity_key')

        # For devices with a separate ramdisk (i.e. non-system-as-root), there must
        # be a copy in ramdisk.
        if info_dict.get("system_root_image") != "true":
            verity_key_ramdisk = os.path.join(input_tmp, 'BOOT', 'RAMDISK',
                                              'verity_key')
            assert os.path.exists(
                verity_key_ramdisk), 'Missing verity_key in ramdisk'

            assert filecmp.cmp(
                verity_key_mincrypt, verity_key_ramdisk, shallow=False), \
                'Mismatching verity_key files in root and ramdisk'
            logging.info('Verified the content of /verity_key in ramdisk')

        # Then verify the verity signed system/vendor/product images, against the
        # verity pubkey in mincrypt format.
        for image in ('system.img', 'vendor.img', 'product.img'):
            image_path = os.path.join(input_tmp, 'IMAGES', image)

            # We are not checking if the image is actually enabled via info_dict (e.g.
            # 'system_verity_block_device=...'). Because it's most likely a bug that
            # skips signing some of the images in signed target-files.zip, while
            # having the top-level verity flag enabled.
            if not os.path.exists(image_path):
                continue

            cmd = [
                'verity_verifier', image_path, '-mincrypt', verity_key_mincrypt
            ]
            proc = common.Run(cmd)
            stdoutdata, _ = proc.communicate()
            assert proc.returncode == 0, \
                'Failed to verify {} with verity_verifier (key: {}):\n{}'.format(
                    image, verity_key_mincrypt, stdoutdata)
            logging.info('Verified %s with verity_verifier (key: %s):\n%s',
                         image, verity_key_mincrypt, stdoutdata.rstrip())

    # Handle the case of Verified Boot 2.0 (AVB).
    if info_dict.get("avb_enable") == "true":
        logging.info('Verifying Verified Boot 2.0 (AVB) images...')

        key = options['verity_key']
        if key is None:
            key = info_dict['avb_vbmeta_key_path']

        ValidatePartitionFingerprints(input_tmp, info_dict)

        # avbtool verifies all the images that have descriptors listed in vbmeta.
        # Using `--follow_chain_partitions` so it would additionally verify chained
        # vbmeta partitions (e.g. vbmeta_system).
        image = os.path.join(input_tmp, 'IMAGES', 'vbmeta.img')
        cmd = [
            info_dict['avb_avbtool'], 'verify_image', '--image', image,
            '--follow_chain_partitions'
        ]

        # Custom images.
        custom_partitions = info_dict.get("avb_custom_images_partition_list",
                                          "").strip().split()

        # Append the args for chained partitions if any.
        for partition in (common.AVB_PARTITIONS +
                          common.AVB_VBMETA_PARTITIONS +
                          tuple(custom_partitions)):
            key_name = 'avb_' + partition + '_key_path'
            if info_dict.get(key_name) is not None:
                if info_dict.get(
                        'ab_update') != 'true' and partition == 'recovery':
                    continue

                # Use the key file from command line if specified; otherwise fall back
                # to the one in info dict.
                key_file = options.get(key_name, info_dict[key_name])
                chained_partition_arg = common.GetAvbChainedPartitionArg(
                    partition, info_dict, key_file)
                cmd.extend(
                    ['--expected_chain_partition', chained_partition_arg])

        # Handle the boot image with a non-default name, e.g. boot-5.4.img
        boot_images = info_dict.get("boot_images")
        if boot_images:
            # we used the 1st boot image to generate the vbmeta. Rename the filename
            # to boot.img so that avbtool can find it correctly.
            first_image_name = boot_images.split()[0]
            first_image_path = os.path.join(input_tmp, 'IMAGES',
                                            first_image_name)
            assert os.path.isfile(first_image_path)
            renamed_boot_image_path = os.path.join(input_tmp, 'IMAGES',
                                                   'boot.img')
            os.rename(first_image_path, renamed_boot_image_path)

        proc = common.Run(cmd)
        stdoutdata, _ = proc.communicate()
        assert proc.returncode == 0, \
            'Failed to verify {} with avbtool (key: {}):\n{}'.format(
                image, key, stdoutdata)

        logging.info('Verified %s with avbtool (key: %s):\n%s', image, key,
                     stdoutdata.rstrip())

        # avbtool verifies recovery image for non-A/B devices.
        if (info_dict.get('ab_update') != 'true'
                and info_dict.get('no_recovery') != 'true'):
            image = os.path.join(input_tmp, 'IMAGES', 'recovery.img')
            key = info_dict['avb_recovery_key_path']
            cmd = [
                info_dict['avb_avbtool'], 'verify_image', '--image', image,
                '--key', key
            ]
            proc = common.Run(cmd)
            stdoutdata, _ = proc.communicate()
            assert proc.returncode == 0, \
                'Failed to verify {} with avbtool (key: {}):\n{}'.format(
                    image, key, stdoutdata)
            logging.info('Verified %s with avbtool (key: %s):\n%s', image, key,
                         stdoutdata.rstrip())