Exemple #1
0
def _get_cert_block_v31(
        config: elftosb_helper.CertificateBlockConfig) -> CertBlockV31:
    root_certs = [
        load_binary(cert_file)
        for cert_file in config.root_certs  # type: ignore
    ]
    user_data = None
    if config.use_isk and config.isk_sign_data_path:
        user_data = load_binary(config.isk_sign_data_path)
    isk_private_key = None
    if config.use_isk:
        assert config.main_root_private_key_file
        isk_private_key = load_binary(config.main_root_private_key_file)
    isk_cert = None
    if config.use_isk:
        assert config.isk_certificate
        isk_cert = load_binary(config.isk_certificate)

    cert_block = CertBlockV31(
        root_certs=root_certs,
        used_root_cert=config.main_root_cert_id,
        user_data=user_data,
        constraints=config.isk_constraint,
        isk_cert=isk_cert,
        ca_flag=not config.use_isk,
        isk_private_key=isk_private_key,
    )
    return cert_block
def _load(cmd_args: dict) -> commands.CmdLoadBase:
    authentication = cmd_args.get('authentication')
    address = int(cmd_args['address'], 0)
    memory_id = int(cmd_args.get('memoryId', '0'), 0)
    if authentication == "hashlocking":
        data = load_binary(cmd_args['file'])
        return commands.CmdLoadHashLocking(address=address,
                                           data=data,
                                           memory_id=memory_id)
    if authentication == "cmac":
        data = load_binary(cmd_args['file'])
        return commands.CmdLoadCmac(address=address,
                                    data=data,
                                    memory_id=memory_id)
    # general non-authenticated load command
    if cmd_args.get('file'):
        data = load_binary(cmd_args['file'])
        return commands.CmdLoad(address=address,
                                data=data,
                                memory_id=memory_id)
    if cmd_args.get('values'):
        values = [int(s, 0) for s in cmd_args['values'].split(',')]
        data = struct.pack(f'<{len(values)}L', *values)
        return commands.CmdLoad(address=address,
                                data=data,
                                memory_id=memory_id)
    raise SPSDKError(f"Unsupported LOAD command args: {cmd_args}")
Exemple #3
0
def test_sdhc(cpu_params: CpuParams, image_name: str, tgt_address: int,
              dcd: Optional[str], plain0_signed1_encr2: int) -> None:
    """ Test creation of unsigned image

    :param cpu_params: processor specific parameters of the test
    :param image_name: filename of the source image; without file extension; without board prefix
    :param tgt_address: address, where the image will be located in the memory (start address of the memory)
    :param dcd: file name of the DCD file to be included in the image; None if no DCD needed
    :param plain0_signed1_encr2: 0 for unsigned; 1 for signed; 2 for encrypted
    """
    image_name = cpu_params.board + '_' + image_name
    # create bootable image object
    app_data = load_binary(cpu_params.data_dir, image_name + '.bin')
    boot_img = BootImgRT(tgt_address, BootImgRT.IVT_OFFSET_OTHER)
    boot_img.fcb = PaddingFCB(0, enabled=False)
    if dcd:
        boot_img.add_dcd_bin(load_binary(cpu_params.data_dir, dcd))

    if plain0_signed1_encr2 == 0:
        boot_img.add_image(app_data)
        suffix = '_sdhc_unsigned.bin'
    elif plain0_signed1_encr2 == 1:
        _to_authenticated_image(cpu_params, boot_img, app_data, 0)
        suffix = '_sdhc_signed.bin'
    elif plain0_signed1_encr2 == 2:
        _to_authenticated_image(cpu_params, boot_img, app_data, 0)
        suffix = '_sdhc_encrypted.bin'
    else:
        assert False

    # write image to disk and to processor
    write_image(cpu_params, image_name + suffix, boot_img)
Exemple #4
0
def create_cert_block(data_dir: str) -> Tuple[CertBlockV2, bytes]:
    """Load 4 certificates and create certificate block

    :param data_dir: absolute path
    :return: tuple with the following items:
    - certificate block with 4 certificates, certificate 0 is selected
    - private key 0, decrypted binary data in PEM format
    """
    # load certificates
    cert_path = os.path.join(data_dir, "keys_certs")
    cert_list = list()
    for cert_index in range(4):
        cert_bin = load_binary(
            cert_path, f"root_k{str(cert_index)}_signed_cert0_noca.der.cert")
        cert_list.append(Certificate(cert_bin))
    # create certification block
    cert_block = CertBlockV2(build_number=1)
    cert_block.add_certificate(cert_list[0])
    # add hashes
    for root_key_index, cert in enumerate(cert_list):
        if cert:
            cert_block.set_root_key_hash(root_key_index, cert)
    # private key that matches selected root cerificate
    priv_key_pem_data = load_binary(
        os.path.join(cert_path, "k0_cert0_2048.pem"))
    return cert_block, priv_key_pem_data
Exemple #5
0
    def load_from_config(
        cls, config: Dict[str, Any]
    ) -> Union["CmdLoad", "CmdLoadHashLocking", "CmdLoadCmac"]:
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        :raises SPSDKError: Invalid configuration field.
        """
        authentication = config.get("authentication")
        address = value_to_int(config["address"], 0)
        memory_id = value_to_int(config.get("memoryId", "0"), 0)
        if authentication == "hashlocking":
            data = load_binary(config["file"])
            return CmdLoadHashLocking.load_from_config(config)  # Backward compatibility
        if authentication == "cmac":
            data = load_binary(config["file"])
            return CmdLoadCmac.load_from_config(config)  # Backward compatibility
        # general non-authenticated load command
        if config.get("file"):
            data = load_binary(config["file"])
            return CmdLoad(address=address, data=data, memory_id=memory_id)
        if config.get("values"):
            values = [value_to_int(s, 0) for s in config["values"].split(",")]
            data = pack(f"<{len(values)}L", *values)
            return CmdLoad(address=address, data=data, memory_id=memory_id)

        raise SPSDKError(f"Unsupported LOAD command args: {config}")
Exemple #6
0
def test_sb_unsigned_otp(data_dir: str, subdir: str, image_name: str) -> None:
    """Test creation of SB file for RT5xx with unsigned image. SBKEK Key for SB file is stored in KEYSTORE.

    :param data_dir: absolute path of the directory with data files for the test
    :param image_name: file name of the unsigned image WITHOUT file extension
    """
    write_shadow_regs(data_dir,
                      [
                          (0x40130194, 0x00000000),  # BOOT_CFG[5]: USE_OTP = 0
                          # MASTER KEY - 000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff
                          (0x401301C0, 0xccddeeff),
                          (0x401301C4, 0x8899aabb),
                          (0x401301C8, 0x44556677),
                          (0x401301CC, 0x00112233),
                          (0x401301D0, 0x0c0d0e0f),
                          (0x401301D4, 0x08090a0b),
                          (0x401301D8, 0x04050607),
                          (0x401301DC, 0x00010203),
                      ])

    sbkek = KeyStore.derive_sb_kek_key(bytes.fromhex(MASTER_KEY))

    adv_params = SBV2xAdvancedParams(dek=b'\xA0' * 32, mac=b'\x0B' * 32, nonce=bytes(16),
                                     timestamp=datetime(2020, month=1, day=31))

    # create SB file boot image
    boot_image = BootImageV21(
        kek=sbkek,
        product_version='1.0.0', component_version='1.0.0', build_number=1,
        # parameters fixed for test only (to have always same output), do not use in production
        advanced_params=adv_params)

    # certificate + private key
    cert_block, priv_key_pem_data = create_cert_block(data_dir)
    boot_image.cert_block = cert_block
    boot_image.private_key_pem_data = priv_key_pem_data

    fcb_data = load_binary(data_dir, FCB_FILE_NAME)
    plain_image_data = load_binary(data_dir, subdir, image_name + '.bin')

    # images are aligned for test purposes only, otherwise export will align with random data
    fcb_data = align_block(fcb_data, 16)
    plain_image_data = align_block(plain_image_data, 16)

    # create boot section 0
    boot_section = BootSectionV2(
        0,
        CmdFill(address=0x10C000, pattern=bytes.fromhex('063040C0')),
        CmdMemEnable(0x10C000, 4, ExtMemId.FLEX_SPI_NOR),
        CmdErase(address=0x8000000, length=0x00800),
        CmdErase(address=0x8001000, length=0x10000),
        CmdLoad(address=0x8000400, data=fcb_data),
        CmdLoad(address=0x8001000, data=plain_image_data))
    boot_image.add_boot_section(boot_section)

    dbg_info = list()  # debug log for analysis of the binary output content
    sb_file = boot_image.export(padding=bytes(8), dbg_info=dbg_info)  # padding for unit test only, to avoid random data
    write_dbg_log(data_dir, image_name + '_otp.sb', dbg_info, TEST_IMG_CONTENT)
    write_sb(data_dir, image_name + '_otp.sb', sb_file, KeyStore(KeySourceType.OTP))
Exemple #7
0
def test_sb_unsigned_keystore(data_dir: str, subdir: str,
                              image_name: str) -> None:
    """Test creation of SB file for RT5xx with unsigned image. SBKEK Key for SB file is stored in KEYSTORE.

    :param data_dir: absolute path of the directory with data files for the test
    :param image_name: file name of the unsigned image WITHOUT file extension
    """
    if not TEST_IMG_CONTENT:
        write_shadow_regs(
            data_dir, [(0x40130194, 0x00000080)])  # BOOT_CFG[5]: USE_PUF = 1

    with open(os.path.join(data_dir, KEYSTORE_SUBDIR, 'SBkek_PUF.txt'),
              'r') as f:
        sbkek_str = f.readline()

    adv_params = SBV2xAdvancedParams(dek=b'\xA0' * 32,
                                     mac=b'\x0B' * 32,
                                     nonce=bytes(16),
                                     timestamp=datetime(2020, month=1, day=31))
    # create boot image
    boot_image = BootImageV21(
        kek=bytes.fromhex(sbkek_str),
        product_version='1.0.0',
        component_version='1.0.0',
        build_number=1,
        # parameters fixed for test only (to have always same output), do not use in production
        advanced_params=adv_params)

    # certificate + private key
    cert_block, priv_key_pem_data = create_cert_block(data_dir)
    boot_image.cert_block = cert_block
    boot_image.private_key_pem_data = priv_key_pem_data

    fcb_data = load_binary(data_dir, FCB_FILE_NAME)
    plain_image_data = load_binary(data_dir, subdir, image_name + '.bin')

    # images are aligned for test purposes only, otherwise export will align with random data
    fcb_data = align_block(fcb_data, 16)
    plain_image_data = align_block(plain_image_data, 16)

    # create boot section 0
    boot_section = BootSectionV2(
        0, CmdFill(address=0x10C000, pattern=bytes.fromhex('063040C0')),
        CmdMemEnable(0x10C000, 4, ExtMemId.FLEX_SPI_NOR),
        CmdErase(address=0x8000000, length=0x10000),
        CmdLoad(address=0x8000400, data=fcb_data),
        CmdLoad(address=0x8001000, data=plain_image_data))
    boot_image.add_boot_section(boot_section)

    dbg_info = list()  # debug log for analysis of the binary output content
    sb_file = boot_image.export(
        padding=bytes(8),
        dbg_info=dbg_info)  # padding for unit test only, to avoid random data
    write_dbg_log(data_dir, image_name + '_keystore.sb', dbg_info,
                  TEST_IMG_CONTENT)
    write_sb(data_dir, image_name + '_keystore.sb', sb_file,
             get_keystore(data_dir))
Exemple #8
0
def test_sb_multiple_sections(cpu_params: CpuParams) -> None:
    """Test creation of SB file with multiple sections.

    :param cpu_params: processor specific parameters of the test
    """
    if (cpu_params.id != ID_RT1050) and (cpu_params.id != ID_RT1060):
        return  # this test case is supported only for RT1050 and RT1060

    # timestamp is fixed for the test, do not not for production
    timestamp = datetime(year=2020,
                         month=4,
                         day=24,
                         hour=15,
                         minute=33,
                         second=32,
                         tzinfo=timezone.utc)

    # 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,
            int.from_bytes(pack("<I", cpu_params.ext_flash_cfg_word0),
                           "little")))
    # enable flexspinor 0x2000;
    sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR))
    # erase 0x60000000..0x60010000;
    # Note: erasing of long flash region may fail on timeout
    # For example this fails on EVK-RT1060: sect.append(CmdErase(EXT_FLASH_ADDR, 0x100000))
    sect.append(CmdErase(EXT_FLASH_ADDR, 0x10000))
    # load 0xf000000f > 0x3000;
    sect.append(
        CmdFill(INT_RAM_ADDR_DATA,
                int.from_bytes(pack("<I", FCB_FLASH_NOR_CFG_WORD), "little")))
    # enable flexspinor 0x3000;
    sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR))
    # load myBinFile > kAbsAddr_Ivt;
    app_data += b"\xdc\xe8\x6d\x5d\xe9\x8c\xf5\x7c"  # 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)
    # add second section, just for the test
    sect2 = BootSectionV1(1, SecureBootFlagsV1.ROM_SECTION_BOOTABLE)
    sect2.append(
        CmdLoad(0x6000F000,
                load_binary(cpu_params.srk_data_dir, "SRK_hash_table.bin")))
    sb.append(sect2)
    #
    write_sb(cpu_params, "sb_file_2_sections" + ".sb", sb)
Exemple #9
0
def generate_master_boot_image(image_conf: click.File) -> None:
    """Generate MasterBootImage from json configuration file."""
    config_data = json.load(image_conf)
    config = elftosb_helper.MasterBootImageConfig(config_data)
    app = load_binary(config.input_image_file)
    load_addr = config.output_image_exec_address
    trustzone = _get_trustzone(config)
    image_type = _get_master_boot_image_type(config)
    dual_boot_version = config.dual_boot_version
    firmware_version = config.firmware_version

    cert_block = None
    signature_provider = None
    if MasterBootImageType.is_signed(image_type):
        cert_config = elftosb_helper.CertificateBlockConfig(config_data)
        root_certs = [
            load_binary(cert_file) for cert_file in cert_config.root_certs  # type: ignore
        ]
        user_data = None
        if cert_config.isk_sign_data_path:
            user_data = load_binary(cert_config.isk_sign_data_path)
        isk_private_key = None
        if cert_config.isk_private_key_file:
            isk_private_key = load_private_key(cert_config.isk_private_key_file)
            assert isinstance(isk_private_key, EllipticCurvePrivateKeyWithSerialization)

        isk_cert = None
        if cert_config.isk_certificate:
            cert_data = load_binary(cert_config.isk_certificate)
            isk_cert = ECC.import_key(cert_data)

        ca_flag = not cert_config.use_isk
        cert_block = CertBlockV3(
            root_certs=root_certs, ca_flag=ca_flag,
            used_root_cert=cert_config.main_root_cert_id, constraints=cert_config.isk_constraint,
            isk_private_key=isk_private_key, isk_cert=isk_cert,  # type: ignore
            user_data=user_data
        )
        if cert_config.use_isk:
            signing_private_key_path = cert_config.isk_private_key_file
        else:
            signing_private_key_path = cert_config.main_root_private_key_file
        signature_provider = SignatureProvider.create(f'type=file;file_path={signing_private_key_path}')

    assert config.master_boot_output_file
    mbi = MasterBootImageN4Analog(
        app=app, load_addr=load_addr, image_type=image_type,
        trust_zone=trustzone, dual_boot_version=dual_boot_version,
        firmware_version=firmware_version,
        cert_block=cert_block,
        signature_provider=signature_provider
    )
    mbi_data = mbi.export()

    write_file(mbi_data, config.master_boot_output_file, mode='wb')
Exemple #10
0
    def from_config(cls, config: Dict[str, Any]) -> "CertBlockV31":
        """Creates instantion of CertBlockV31 from configuration.

        :param config: Input standard configuration.
        :return: Instantion of CertBlockV3.1
        :raises SPSDKError: If found gap in certificates from config file.
        """
        root_certificates_loaded: List[Optional[str]] = [
            config.get(f"rootCertificate{idx}File") for idx in range(4)
        ]
        # filter out None and empty values
        root_certificates = list(filter(None, root_certificates_loaded))
        for org, filtered in zip(root_certificates_loaded, root_certificates):
            if org != filtered:
                raise SPSDKError(
                    "There are gaps in rootCertificateXFile definition")

        main_root_cert_id = config.get("mainRootCertId", 0)
        main_root_private_key_file = config.get("mainRootCertPrivateKeyFile")
        use_isk = config.get("useIsk", False)
        isk_certificate = config.get("signingCertificateFile")
        isk_constraint = value_to_int(
            config.get("signingCertificateConstraint", "0"))
        isk_sign_data_path = config.get("signCertData")

        root_certs = [
            misc.load_binary(cert_file) for cert_file in root_certificates
        ]
        user_data = None
        isk_private_key = None
        isk_cert = None

        if use_isk:
            assert isk_certificate and main_root_private_key_file
            if isk_sign_data_path:
                user_data = misc.load_binary(isk_sign_data_path)
            isk_private_key = misc.load_binary(main_root_private_key_file)
            isk_cert = misc.load_binary(isk_certificate)

        cert_block = CertBlockV31(
            root_certs=root_certs,
            used_root_cert=main_root_cert_id,
            user_data=user_data,
            constraints=isk_constraint,
            isk_cert=isk_cert,
            ca_flag=not use_isk,
            isk_private_key=isk_private_key,
        )

        return cert_block
Exemple #11
0
def test_flexspi_conf_block_fcb(data_dir) -> None:
    # default object created
    fcb = FlexSPIConfBlockFCB()
    assert fcb.info()
    assert fcb.export()
    assert fcb == FlexSPIConfBlockFCB.parse(fcb.export())
    fcb.padding_len = 10
    assert len(fcb.export()) == fcb.space
    # FCB from RT105x EVK
    fcb_path = os.path.join(data_dir, 'rt105x_flex_spi.fcb')
    fcb = FlexSPIConfBlockFCB.parse(load_binary(fcb_path))
    assert fcb.info()
    fcb.padding_len = 0
    compare_bin_files(fcb_path, fcb.export())
    fcb.enabled = False
    assert fcb.size == 0
    assert fcb.export() == b''
    # invalid tag
    with pytest.raises(ValueError):
        FlexSPIConfBlockFCB.parse(b'\x00' * 512)
    # invalid version
    with pytest.raises(ValueError):
        FlexSPIConfBlockFCB.parse(FlexSPIConfBlockFCB.TAG + b'\x00' * 512)
    # insufficient length
    with pytest.raises(ValueError):
        FlexSPIConfBlockFCB.parse(FlexSPIConfBlockFCB.TAG +
                                  FlexSPIConfBlockFCB.VERSION[::-1])
Exemple #12
0
def test_ram_encrypted_keystore(data_dir: str, image_file_name: str,
                                ram_addr: int) -> None:
    """Test encrypted load-to-RAM image with key stored in key-store

    :param data_dir: absolute path with data files
    :param image_file_name: name of the input image file (including extension)
    :param ram_addr: address in RAM, where the image should be located
    """
    path = os.path.join(data_dir, INPUT_IMAGES_SUBDIR, image_file_name)
    org_data = load_binary(path)

    # load keystore with HMAC user key
    key_store = get_keystore(data_dir)

    cert_block, priv_key_pem_data = create_cert_block(data_dir)

    with open(os.path.join(data_dir, KEYSTORE_SUBDIR, "userkey.txt"),
              "r") as f:
        hmac_user_key = f.readline()

    mbi = Mbi_EncryptedRamRtxxx(
        app=org_data,
        load_addr=ram_addr,
        trust_zone=TrustZone.disabled(),
        cert_block=cert_block,
        priv_key_data=priv_key_pem_data,
        hmac_key=hmac_user_key,
        key_store=key_store,
        ctr_init_vector=ENCR_CTR_IV,
    )

    out_image_file_name = image_file_name.replace("_unsigned.bin",
                                                  "_encr_keystore.bin")
    write_image(data_dir, out_image_file_name, mbi.export())
Exemple #13
0
def test_ram_signed_otp(data_dir: str, image_file_name: str,
                        ram_addr: int) -> None:
    """Create signed load-to-RAM image with keys stored in OTP

    :param data_dir: absolute path with data files
    :param image_file_name: name of the input image file (including extension)
    :param ram_addr: address in RAM, where the image should be located
    """
    # read unsigned image (must be built without boot header)
    path = os.path.join(data_dir, INPUT_IMAGES_SUBDIR, image_file_name)
    unsigned_img = load_binary(path)

    keystore = KeyStore(KeySourceType.OTP)

    cert_block, priv_key_pem_data = create_cert_block(data_dir)

    mbi = Mbi_PlainSignedRamRtxxx(
        app=unsigned_img,
        load_addr=ram_addr,
        key_store=keystore,
        hmac_key=MASTER_KEY,
        trust_zone=TrustZone.disabled(),
        cert_block=cert_block,
        priv_key_data=priv_key_pem_data,
    )

    out_image_file_name = image_file_name.replace("_unsigned.bin",
                                                  "_signed_otp.bin")
    write_image(data_dir, out_image_file_name, mbi.export())
Exemple #14
0
    def mix_load_from_config(self, config: Dict[str, Any]) -> None:
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        """
        self.cert_block = CertBlockV2.from_config(config)
        self.priv_key_data = load_binary(config["mainCertPrivateKeyFile"])
Exemple #15
0
def test_ram_signed_keystore(data_dir: str, image_file_name: str, ram_addr: int) -> None:
    """Create signed load-to-RAM image with keys stored in key-store

    :param data_dir: absolute path with data files
    :param image_file_name: name of the input image file (including extension)
    :param ram_addr: address in RAM, where the image should be located
    """
    # read unsigned image (must be built without boot header)
    path = os.path.join(data_dir, INPUT_IMAGES_SUBDIR, image_file_name)
    org_data = load_binary(path)

    cert_block, priv_key_pem_data = create_cert_block(data_dir)

    key_store = get_keystore(data_dir)

    with open(os.path.join(data_dir, KEYSTORE_SUBDIR, 'userkey.txt'), 'r') as f:
        hmac_user_key = f.readline()

    mbi = MasterBootImage(app=org_data,
                          image_type=MasterBootImageType.SIGNED_RAM_IMAGE,
                          load_addr=ram_addr,
                          trust_zone=TrustZone.disabled(),
                          key_store=key_store,
                          cert_block=cert_block,
                          priv_key_pem_data=priv_key_pem_data,
                          hmac_key=hmac_user_key)

    out_image_file_name = image_file_name.replace('_unsigned.bin', '_signed_keystore.bin')
    write_image(data_dir, out_image_file_name, mbi.export())
Exemple #16
0
def _load_private_key(data_dir: str, filename: str) -> bytes:
    """Load PEM private key from data_dir

    :param filename: private key file name to load
    :return: private key as binary data in PEM format, decrypted
    """
    return load_binary(os.path.join(data_dir, 'keys_and_certs', filename))
Exemple #17
0
 def _load_preset_file(self, preset_file: str, family: str) -> None:
     try:
         tz_config = load_configuration(preset_file)
         self.tz = TrustZone.from_config(tz_config)
     except SPSDKError:
         tz_bin = load_binary(preset_file)
         self.tz = TrustZone.from_binary(family=family, raw_data=tz_bin)
Exemple #18
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)
Exemple #19
0
    def load_from_config(cls, config: Dict[str, Any]) -> "SecureBinary31":
        """Creates instantion of SecureBinary31 from configuration.

        :param config: Input standard configuration.
        :return: Instantion of Secure Binary V3.1 class
        """
        container_keyblob_enc_key_path = config.get(
            "containerKeyBlobEncryptionKey")
        is_nxp_container = config.get("isNxpContainer", False)
        description = config.get("description")
        kdk_access_rights = value_to_int(config.get("kdkAccessRights", 0))
        container_configuration_word = value_to_int(
            config.get("containerConfigurationWord", 0))
        firmware_version = value_to_int(config.get("firmwareVersion", 1))

        commands = config["commands"]
        is_encrypted = config.get("isEncrypted", True)
        timestamp = config.get("timestamp")
        if timestamp:  # re-format it
            timestamp = value_to_int(timestamp)

        cert_block = CertBlockV31.from_config(config)

        # if use_isk is set, we use for signing the ISK certificate instead of root
        signing_key_path = (config.get("signingCertificatePrivateKeyFile")
                            if cert_block.isk_certificate else
                            config.get("mainRootCertPrivateKeyFile"))
        curve_name = (config.get("iskCertificateEllipticCurve")
                      if cert_block.isk_certificate else
                      config.get("rootCertificateEllipticCurve"))
        assert curve_name and isinstance(curve_name, str)
        assert signing_key_path
        signing_key = load_binary(
            signing_key_path) if signing_key_path else None
        assert signing_key

        pck = None
        if is_encrypted:
            assert container_keyblob_enc_key_path
            pck = bytes.fromhex(load_text(container_keyblob_enc_key_path))

        # Create SB3 object
        sb3 = SecureBinary31(
            pck=pck,
            cert_block=cert_block,
            curve_name=curve_name,
            kdk_access_rights=kdk_access_rights,
            firmware_version=firmware_version,
            description=description,
            is_nxp_container=is_nxp_container,
            flags=container_configuration_word,
            signing_key=signing_key,
            timestamp=timestamp,
            is_encrypted=is_encrypted,
        )

        # Add commands into the SB3 object
        sb3.sb_commands.load_from_config(commands)

        return sb3
Exemple #20
0
def generate_master_boot_image(image_conf: click.File) -> None:
    """Generate MasterBootImage from json configuration file."""
    config_data = json.load(image_conf)
    config = elftosb_helper.MasterBootImageConfig(config_data)
    app = load_binary(config.input_image_file)
    load_addr = config.output_image_exec_address
    trustzone = _get_trustzone(config)
    image_type = _get_master_boot_image_type(config)
    dual_boot_version = config.dual_boot_version
    firmware_version = config.firmware_version

    cert_block = None
    signature_provider = None
    if MasterBootImageType.is_signed(image_type):
        cert_config = elftosb_helper.CertificateBlockConfig(config_data)
        cert_block = _get_cert_block_v31(cert_config)
        if cert_config.use_isk:
            signing_private_key_path = cert_config.isk_private_key_file
        else:
            signing_private_key_path = cert_config.main_root_private_key_file
        signature_provider = SignatureProvider.create(
            f'type=file;file_path={signing_private_key_path}')

    mbi = MasterBootImageN4Analog(app=app,
                                  load_addr=load_addr,
                                  image_type=image_type,
                                  trust_zone=trustzone,
                                  dual_boot_version=dual_boot_version,
                                  firmware_version=firmware_version,
                                  cert_block=cert_block,
                                  signature_provider=signature_provider)
    mbi_data = mbi.export()

    write_file(mbi_data, config.master_boot_output_file, mode='wb')
Exemple #21
0
def test_load_binary(data_dir):
    """Test loading binary files using load_binary and load_file."""
    data = load_binary(data_dir, "file.bin")
    data2 = load_file(data_dir, "file.bin", mode="rb")

    assert data == data2
    assert data == bytes(i for i in range(10))
Exemple #22
0
def test_secure_binary3_validate(data_dir):
    """Test of validation function for Secure Binary class."""

    rot = [
        load_binary(os.path.join(data_dir, "ecc_secp256r1_priv_key.pem"))
        for x in range(4)
    ]
    cert_blk = CertBlockV31(root_certs=rot, ca_flag=1)

    sb3 = SecureBinary31(
        curve_name="secp256r1",
        cert_block=cert_blk,
        firmware_version=1,
        signing_key=rot[0],
        is_encrypted=False,
    )
    sb3.validate()
    with pytest.raises(SPSDKError):
        sb3.signing_key = None
        sb3.validate()
    with pytest.raises(SPSDKError):
        sb3.signing_key = "Invalid"
        sb3.validate()
    sb3.signing_key = rot[0]
    sb3.validate()
Exemple #23
0
def init_flashloader(cpu_params: CpuParams) -> McuBoot:
    """Load an execute flash-loader binary in i.MX-RT
       The function signs the flashloader if needed (if HAB enabled)

       :param cpu_params: processor specific parameters of the test
       :return: McuBoot instance to communicate with flash-loader
       :raises ConnectionError: if connection cannot be established
       """
    devs = mboot_scan_usb(cpu_params.com_processor_name
                          )  # check whether flashloader is already running
    if len(devs) == 0:
        # if flash-loader not running yet, it must be downloaded to RAM and launched
        flshldr_img = BootImgRT.parse(
            load_binary(cpu_params.data_dir, 'ivt_flashloader.bin'))

        devs = sdp_scan_usb(cpu_params.com_processor_name)
        if len(devs) != 1:
            raise ConnectionError('Cannot connect to ROM bootloader')

        with SDP(devs[0], cmd_exception=True) as sd:
            assert sd.is_opened
            try:
                sd.read(INT_RAM_ADDR_CODE, 4)  # dummy read to receive response
            except SdpCommandError:  # there is an exception if HAB is locked, cause read not supported
                pass

            if (sd.status_code
                    == StatusCode.HAB_IS_LOCKED) and (sd.response_value
                                                      == ResponseValue.LOCKED):
                auth_flshldr_img = BootImgRT(flshldr_img.address,
                                             BootImgRT.IVT_OFFSET_OTHER)
                _to_authenticated_image(
                    cpu_params, auth_flshldr_img, flshldr_img.app.data, 0,
                    flshldr_img.ivt.app_address
                )  # entry addr cannot be detected from img
            else:
                auth_flshldr_img = flshldr_img
            assert sd.write_file(auth_flshldr_img.address,
                                 auth_flshldr_img.export())
            try:
                assert sd.jump_and_run(auth_flshldr_img.address +
                                       auth_flshldr_img.ivt_offset)
            except SdpCommandError:
                pass  # SDP may return an exception if HAB locked

        for _ in range(10):  # wait 10 sec until flash-loader is inited
            sleep(1)
            # Scan for MCU-BOOT device
            devs = mboot_scan_usb(cpu_params.com_processor_name)
            if len(devs) == 1:
                break

    if len(devs) != 1:
        raise ConnectionError('Cannot connect to Flash-Loader')

    result = McuBoot(devs[0], cmd_exception=True)
    result.open()
    assert result.is_opened
    result.reopen = False  # reopen not supported for RT1050???
    return result
Exemple #24
0
def test_dac_packet_info(data_dir):
    data = load_binary(data_dir, 'sample_dac.bin')
    dac = DebugAuthenticationChallenge.parse(data, offset=0)
    dac_info = dac.info()
    assert '1.0' in dac_info
    assert 'FF00FF00' in dac_info
    assert 'AA55AA55' in dac_info
Exemple #25
0
def test_dac_packet_info(data_dir):
    data = load_binary(data_dir, "sample_dac.bin")
    dac = DebugAuthenticationChallenge.parse(data, offset=0)
    dac_info = dac.info()
    assert "1.0" in dac_info
    assert "FF00FF00" in dac_info
    assert "AA55AA55" in dac_info
Exemple #26
0
def test_generate_csf_img(cpu_params: CpuParams, srk_key_index: int, cert_name_prefix: str, cert_index: int,
                          key_size: int = 2048) -> None:
    """Generate additional CSF or IMG certificate for selected SRK key

    :param cpu_params: processor specific parameters of the test
    :param srk_key_index: index of SRK, for which new certificate is going to be generated
    :param cert_name_prefix: prefix/type of the generated certificate: either 'CSF' or 'IMG'
    :param cert_index: index of the generated certificate
    :param key_size: size of the generated key in bits, 2048 by default
    """
    # validate arguments
    assert 1 <= srk_key_index <= 4
    assert cert_name_prefix == 'CSF' or cert_name_prefix == 'IMG'
    assert 1 <= cert_index
    # build names
    base_key_name = f'_sha256_{str(key_size)}_65537_v3_'  # middle path of the output filename
    srk_name = f'SRK{srk_key_index}' + base_key_name + 'ca'
    out_name = cert_name_prefix + str(srk_key_index) + '_' + str(cert_index) + base_key_name + 'usr'
    out_key_path = os.path.join(cpu_params.keys_data_dir, out_name + '_key')
    # generate private key
    gen_priv_key = generate_rsa_private_key(key_size=key_size)
    save_private_key(gen_priv_key, out_key_path + '.pem', password=PRIV_KEY_PASSWORD, encoding=Encoding.PEM)
    save_private_key(gen_priv_key, out_key_path + '.der', password=PRIV_KEY_PASSWORD, encoding=Encoding.DER)
    # generate public key
    gen_pub_key = generate_rsa_public_key(gen_priv_key)
    # load private key of the issuer (SRK)
    srk_priv_key = load_pem_private_key(load_binary(cpu_params.keys_data_dir, srk_name + '_key.pem'),
                                        password=PRIV_KEY_PASSWORD, backend=default_backend())
    # generate certificate
    gen_cert = generate_certificate(x509_common_name(out_name), x509_common_name(srk_name), gen_pub_key,
                                    srk_priv_key, serial_number=0x199999A7, if_ca=False, duration=3560)
    save_crypto_item(gen_cert, os.path.join(cpu_params.cert_data_dir, out_name + '_crt.pem'), Encoding.PEM)
    save_crypto_item(gen_cert, os.path.join(cpu_params.cert_data_dir, out_name + '_crt.der'), Encoding.DER)
Exemple #27
0
def test_ram_encrypted_otp(data_dir: str, image_file_name: str, ram_addr: int) -> None:
    """Test encrypted load-to-RAM image with key stored in OTP

    :param data_dir: absolute path with data files
    :param image_file_name: name of the input image file (including extension)
    :param ram_addr: address in RAM, where the image should be located
    """
    path = os.path.join(data_dir, INPUT_IMAGES_SUBDIR, image_file_name)
    org_data = load_binary(path)
    key_store = KeyStore(KeySourceType.OTP)

    cert_block, priv_key_pem_data = create_cert_block(data_dir)

    with open(os.path.join(data_dir, KEYSTORE_SUBDIR, 'userkey.txt'), 'r') as f:
        hmac_user_key = f.readline()

    mbi = MasterBootImage(app=org_data,
                          image_type=MasterBootImageType.ENCRYPTED_RAM_IMAGE,
                          load_addr=ram_addr,
                          trust_zone=TrustZone.disabled(),
                          cert_block=cert_block,
                          priv_key_pem_data=priv_key_pem_data,
                          hmac_key=hmac_user_key,
                          key_store=key_store,
                          ctr_init_vector=ENCR_CTR_IV)

    out_image_file_name = image_file_name.replace('_unsigned.bin', '_encr_otp.bin')
    write_image(data_dir, out_image_file_name, mbi.export())
Exemple #28
0
def test_bee_unsigned_sw_key(cpu_params: CpuParams) -> None:
    """Test encrypted XIP unsigned image with user keys.
    It is supposed the SRK_KEY_SEL fuse is burned.
    It is supposed the user key is burned in SW_GP2 fuses.

    :param cpu_params: processor specific parameters of the test
    """
    img = BootImgRT(EXT_FLASH_ADDR)
    img.add_image(
        load_binary(cpu_params.data_dir,
                    f'{cpu_params.board}_iled_blinky_ext_FLASH.bin'))
    # the following parameters are fixed for the test only, to produce stable result; for production use random number
    cntr1 = bytes.fromhex('112233445566778899AABBCC00000000')
    kib_key1 = bytes.fromhex('C1C2C3C4C5C6C7C8C9CACBCCCDCECFC0')
    kib_iv1 = bytes.fromhex('1112131415161718191A1B1C1D1E1F10')
    cntr2 = bytes.fromhex('2233445566778899AABBCCDD00000000')
    kib_key2 = bytes.fromhex('C1C2C3C4C5C6C7C8C9CACBCCCDCECFC2')
    kib_iv2 = bytes.fromhex('2122232425262728292A2B2C2D2E2F20')
    # Add two regions as an example (even this is probably not real use case)
    # BEE region 0
    sw_key = bytes.fromhex('0123456789abcdeffedcba9876543210')
    region = BeeRegionHeader(BeeProtectRegionBlock(counter=cntr1), sw_key,
                             BeeKIB(kib_key1, kib_iv1))
    region.add_fac(BeeFacRegion(EXT_FLASH_ADDR + 0x1000, 0x2000))
    region.add_fac(BeeFacRegion(EXT_FLASH_ADDR + 0x3800, 0x800))
    img.bee.add_region(region)
    # BEE region 1 (this is just example, the is no code in the region)
    sw_key = bytes.fromhex('F123456789abcdeffedcba987654321F')
    region = BeeRegionHeader(BeeProtectRegionBlock(counter=cntr2), sw_key,
                             BeeKIB(kib_key2, kib_iv2))
    region.add_fac(BeeFacRegion(EXT_FLASH_ADDR + 0x100000, 0x1000))
    img.bee.add_region(region)
    #
    out_name = cpu_params.board + '_iled_blinky_ext_FLASH_bee_userkey_unsigned.bin'
    write_image(cpu_params, out_name, img)
Exemple #29
0
def _load_key_blob_handler(cmd_args: dict) -> commands.CmdLoadKeyBlob:
    data = load_binary(cmd_args['file'])
    offset = int(cmd_args['offset'], 0)
    key_wrap_name = cmd_args['wrappingKeyId']
    key_wrap_id = commands.CmdLoadKeyBlob.KeyWraps[key_wrap_name]
    return commands.CmdLoadKeyBlob(offset=offset,
                                   data=data,
                                   key_wrap_id=key_wrap_id)
Exemple #30
0
    def load_from_config(cls, config: Dict[str, Any]) -> "CmdProgIfr":
        """Load configuration from dictionary.

        :param config: Dictionary with configuration fields.
        :return: Command object loaded from configration.
        """
        address = value_to_int(config["address"], 0)
        data = load_binary(config["file"])
        return CmdProgIfr(address=address, data=data)