Example #1
0
    def align(size: int) -> int:
        """Align given size to block size.

        :param size: in bytes
        :return: size aligned up to block size
        """
        return misc.align(size, SecBootBlckSize.BLOCK_SIZE)
Example #2
0
def test_sb(cpu_params: CpuParams) -> None:
    """Test creation of SB file.

    :param cpu_params: processor specific parameters of the test
    """
    # timestamp is fixed for the test, do not not for production
    timestamp = datetime(year=2020, month=4, day=24, hour=16, minute=33, second=32)

    # load application to add into SB
    img_name = f'{cpu_params.board}_iled_blinky_ext_FLASH_unsigned_nofcb'
    app_data = load_binary(cpu_params.data_dir, OUTPUT_IMAGES_SUBDIR, img_name + '.bin')
    boot_img = BootImgRT.parse(app_data)  # parse to retrieve IVT offset

    sb = SecureBootV1(version=SB_FILE_VERSION, timestamp=timestamp)
    sect = BootSectionV1(0, SecureBootFlagsV1.ROM_SECTION_BOOTABLE)
    # load 0xc0233007 > 0x2000;
    sect.append(CmdFill(INT_RAM_ADDR_DATA, pack("<I", cpu_params.ext_flash_cfg_word0)))
    # enable flexspinor 0x2000;
    sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR))
    # erase 0x60000000..0x60100000;
    sect.append(CmdErase(EXT_FLASH_ADDR, align(boot_img.ivt_offset + boot_img.size, 0x1000)))
    # load 0xf000000f > 0x3000;
    sect.append(CmdFill(INT_RAM_ADDR_DATA, pack("<I", FCB_FLASH_NOR_CFG_WORD)))
    # enable flexspinor 0x3000;
    sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR))
    # load myBinFile > kAbsAddr_Ivt;
    app_data += b'\x49\x20\x93\x8e\x89\x8F\x43\x88'  # this is random padding fixed for the test, not use for production
    sect.append(CmdLoad(EXT_FLASH_ADDR + boot_img.ivt_offset, app_data))
    #
    sb.append(sect)
    #
    write_sb(cpu_params, img_name + '.sb', sb)
Example #3
0
    def export(
            self,
            header_padding8: Optional[bytes] = None,
            auth_padding: Optional[bytes] = None,
            dbg_info: DebugInfo = DebugInfo.disabled(),
    ) -> bytes:
        """Serialization to binary form.

        :param header_padding8: optional header padding, 8-bytes; recommended to use None to apply random value
        :param auth_padding: optional padding used after authentication; recommended to use None to apply random value
        :param dbg_info: instance allowing to debug generated output
        :return: serialize the instance into binary data
        :raises SPSDKError: Invalid section data
        :raises SPSDKError: Invalid padding length
        """
        self.update()
        self.validate()
        dbg_info.append_section("SB-FILE-1.x")
        data = self._header.export(padding8=header_padding8, dbg_info=dbg_info)
        # header table
        dbg_info.append_section("Sections-Header-Table")
        for sect_hdr in self._sections_hdr_table:
            sect_hdr_data = sect_hdr.export()
            dbg_info.append_binary_data("Section-Header-Item", sect_hdr_data)
            data += sect_hdr_data
        # sections
        dbg_info.append_section("Sections")
        for sect in self._sections:
            sect_data = sect.export(dbg_info)
            if len(sect_data) != sect.size:
                raise SPSDKError("Invalid section data")
            data += sect_data
        # authentication: SHA1
        auth_code = crypto_backend().hash(data, "sha1")
        dbg_info.append_binary_section("SHA1", auth_code)
        data += auth_code
        # padding
        padding_len = align(len(auth_code),
                            SecBootBlckSize.BLOCK_SIZE) - len(auth_code)
        if auth_padding is None:
            auth_padding = crypto_backend().random_bytes(padding_len)
        if padding_len != len(auth_padding):
            raise SPSDKError("Invalid padding length")
        data += auth_padding
        dbg_info.append_binary_section("padding", auth_padding)
        return data
Example #4
0
def _to_authenticated_image(cpu_params: CpuParams, boot_img: BootImgRT, app_data: bytes, srk_key_index: int,
                            entry_addr: int = -1, dek: Optional[bytes] = None, nonce: Optional[bytes] = None) -> None:
    """Configures given bootable image to authenticated image or encrypted image

    :param cpu_params: processor specific parameters of the test
    :param boot_img: bootable image to be updated (converted to signed or encrypted)
    :param app_data: data of the binary application
    :param srk_key_index: index of the SRK key used, 0-3
    :param entry_addr: start address of the application; -1 to detect the address from the image
    :param dek: key for encrypted image:
                - None if image is not encrypted
                - empty value for image encrypted with random key
                - full key for test purposes
    :param nonce: optional initialization vector for AES encryption; None to use random value (recommended)
    :return: BootImageRT with application  configured as signed or encrypted
    """
    assert 0 <= srk_key_index <= 3
    boot_img.add_image(app_data, address=entry_addr, dek_key=dek, nonce=nonce)
    # test method `decrypted_app_data`
    if dek:
        decr_app = boot_img.decrypted_app_data
        assert (len(decr_app) == align(len(app_data), MAC.AES128_BLK_LEN)) and (decr_app[:len(app_data)] == app_data)
    else:
        assert boot_img.decrypted_app_data == app_data
    csf_prefix = 'CSF' + str(srk_key_index + 1) + '_1_sha256_2048_65537_v3_usr_'
    img_prefix = 'IMG' + str(srk_key_index + 1) + '_1_sha256_2048_65537_v3_usr_'
    csf_priv_key = load_pem_private_key(load_binary(cpu_params.keys_data_dir, csf_prefix + 'key.pem'),
                                        password=PRIV_KEY_PASSWORD, backend=default_backend())
    img_priv_key = load_pem_private_key(load_binary(cpu_params.keys_data_dir, img_prefix + 'key.pem'),
                                        password=PRIV_KEY_PASSWORD, backend=default_backend())
    csf_priv_key_data = csf_priv_key.private_bytes(encoding=Encoding.PEM, format=PrivateFormat.PKCS8,
                                                   encryption_algorithm=NoEncryption())
    img_priv_key_data = img_priv_key.private_bytes(encoding=Encoding.PEM, format=PrivateFormat.PKCS8,
                                                   encryption_algorithm=NoEncryption())
    if dek is None:
        boot_img.add_csf_standard_auth(CSF_VERSION, srk_table4(cpu_params), srk_key_index,
                                       load_binary(cpu_params.cert_data_dir, csf_prefix + 'crt.pem'), csf_priv_key_data,
                                       load_binary(cpu_params.cert_data_dir, img_prefix + 'crt.pem'), img_priv_key_data)
    else:
        boot_img.add_csf_encrypted(CSF_VERSION, srk_table4(cpu_params), srk_key_index,
                                   load_binary(cpu_params.cert_data_dir, csf_prefix + 'crt.pem'), csf_priv_key_data,
                                   load_binary(cpu_params.cert_data_dir, img_prefix + 'crt.pem'), img_priv_key_data)
Example #5
0
    def export(
        self,
        header_padding8: Optional[bytes] = None,
        auth_padding: Optional[bytes] = None,
        dbg_info: DebugInfo = DebugInfo.disabled()
    ) -> bytes:
        """Serialization to binary form.

        :param header_padding8: optional header padding, 8-bytes; recommended to use None to apply random value
        :param auth_padding: optional padding used after authentication; recommended to use None to apply random value
        :param dbg_info: instance allowing to debug generated output
        :return: serialize the instance into binary data
        """
        self.update()
        self.validate()
        dbg_info.append_section('SB-FILE-1.x')
        data = self._header.export(padding8=header_padding8, dbg_info=dbg_info)
        # header table
        dbg_info.append_section('Sections-Header-Table')
        for sect_hdr in self._sections_hdr_table:
            sect_hdr_data = sect_hdr.export()
            dbg_info.append_binary_data('Section-Header-Item', sect_hdr_data)
            data += sect_hdr_data
        # sections
        dbg_info.append_section('Sections')
        for sect in self._sections:
            sect_data = sect.export(dbg_info)
            assert len(sect_data) == sect.size
            data += sect_data
        # authentication: SHA1
        auth_code = crypto_backend().hash(data, 'sha1')
        dbg_info.append_binary_section('SHA1', auth_code)
        data += auth_code
        # padding
        padding_len = align(len(auth_code),
                            SecBootBlckSize.BLOCK_SIZE) - len(auth_code)
        if auth_padding is None:
            auth_padding = crypto_backend().random_bytes(padding_len)
        assert padding_len == len(auth_padding)
        data += auth_padding
        dbg_info.append_binary_section('padding', auth_padding)
        return data
Example #6
0
def test_align(test_input: int, alignment: int, expected: int):
    assert align(test_input, alignment) == expected
Example #7
0
def _burn_image_to_flash(
    cpu_params: CpuParams,
    img: BootImgRT,
    img_data: bytes,
    otpmk_bee_regions: Tuple[BeeFacRegion, ...] = tuple()
) -> None:
    """Burn image into external FLASH. This function is called only in production mode.

    :param cpu_params: processor specific parameters of the test
    :param img: RT10xx image instance
    :param img_data: exported image data
    :param otpmk_bee_regions: optional list of BEE regions for BEE OTPMK encryption
    """
    assert TEST_IMG_CONTENT is False

    # start FLASH loader
    mboot = init_flashloader(cpu_params)
    assert mboot.get_property(PropertyTag.CURRENT_VERSION)
    # verify SRK fuses are properly burned
    if VERIFY_SRK_FUSES:
        assert verify_srk_fuses(mboot, srk_table4(cpu_params))

    # ### Configure external FLASH on EVK: flex-spi-nor using options on address 0x2000 ###
    # call "%blhost%" -u 0x15A2,0x0073 -j -- fill-memory 0x2000 4 0xC0233007 word
    assert mboot.fill_memory(INT_RAM_ADDR_DATA, 4,
                             cpu_params.ext_flash_cfg_word0)
    # call "%blhost%" -u 0x15A2,0x0073 -j -- fill-memory 0x2004 4 0x00000000 word
    assert mboot.fill_memory(INT_RAM_ADDR_DATA + 4, 4,
                             cpu_params.ext_flash_cfg_word1)
    # call "%blhost%" -u 0x15A2,0x0073 -j -- configure-memory 9 0x2000
    assert mboot.configure_memory(INT_RAM_ADDR_DATA, ExtMemId.FLEX_SPI_NOR)

    if not img.fcb.enabled:
        write_addr_ofs = img.ivt_offset
        imgdata_offset = 0
    elif isinstance(img.fcb, PaddingFCB):
        write_addr_ofs = img.BEE_OFFSET if img.bee_encrypted else img.ivt_offset
        imgdata_offset = img.BEE_OFFSET if img.bee_encrypted else img.ivt_offset
    elif isinstance(img.fcb, FlexSPIConfBlockFCB):
        write_addr_ofs = 0
        imgdata_offset = 0
    else:
        assert False

    # ### Erase memory before writing image ###
    # call "%blhost%" -u 0x15A2,0x0073 -j -- flash-erase-region 0x60000000 21000 9
    size = align(len(img_data) + write_addr_ofs, 0x1000)
    assert mboot.flash_erase_region(EXT_FLASH_ADDR, size,
                                    ExtMemId.FLEX_SPI_NOR)

    if not img.fcb.enabled or isinstance(
            img.fcb, PaddingFCB):  # FCB not part of the image
        # ### Use tag 0xF000000F to notify Flashloader to program FlexSPI NOR config block to the start of device###
        # call "%blhost%" -u 0x15A2,0x0073 -j -- fill-memory 0x3000 4 0xF000000F word
        assert mboot.fill_memory(INT_RAM_ADDR_DATA, 4, FCB_FLASH_NOR_CFG_WORD)
        # ### Program configuration block ###
        # call "%blhost%" -u 0x15A2,0x0073 -j -- configure-memory 9 0x3000
        assert mboot.configure_memory(INT_RAM_ADDR_DATA, ExtMemId.FLEX_SPI_NOR)
        # read flex_spi.fcb
        mem = mboot.read_memory(EXT_FLASH_ADDR, 512, ExtMemId.FLEX_SPI_NOR)
        with open(os.path.join(cpu_params.data_dir, 'flex_spi.fcb'),
                  'wb') as f:
            f.write(mem)

        if otpmk_bee_regions:
            assert img.address == EXT_FLASH_ADDR  # is applicable for XIP images only
            _init_otpmk_bee_regions(mboot, otpmk_bee_regions)

    else:
        assert len(otpmk_bee_regions) == 0

    # @echo ### Write image ###
    # call "%blhost%" -u 0x15A2,0x0073 -j -- write-memory 0x60001000 image.bin 9
    mboot.write_memory(EXT_FLASH_ADDR + write_addr_ofs,
                       img_data[imgdata_offset:])

    # for HAB encrypted image write KEY BLOB
    if img.dek_key:
        # call "blhost" -u 0x15A2,0x0073 -j -- generate-key-blob hab_dek.bin blob.bin
        blob = mboot.generate_key_blob(img.dek_key)
        tgt_address = EXT_FLASH_ADDR + img.dek_img_offset
        # call "blhost" -u 0x15A2,0x0073 -j -- write-memory 0x60008000 blob.bin 9
        assert mboot.write_memory(tgt_address, blob, ExtMemId.FLEX_SPI_NOR)

    if AUTHENTICATE and (img.address
                         == EXT_FLASH_ADDR) and not otpmk_bee_regions:
        mboot.close()
        hab_audit_xip_app(cpu_params, True)
    else:
        # detect XIP image
        app_data = img.decrypted_app_data
        initial_pc = int.from_bytes(app_data[4:8], byteorder="little")
        if img.address == EXT_FLASH_ADDR:  # if XIP
            # run XIP image immediately
            stack_ptr = int.from_bytes(app_data[:4], byteorder="little")
            assert mboot.execute(initial_pc, EXT_FLASH_ADDR + img.ivt_offset,
                                 stack_ptr)

        mboot.close()
Example #8
0
 def raw_size(self) -> int:
     """Aligned size of the certificate block."""
     size = CertBlockHeader.SIZE
     size += self._header.cert_table_length
     size += self.RKH_SIZE * self.RKHT_SIZE
     return misc.align(size, self.alignment)