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}")
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)
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
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}")
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))
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))
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)
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')
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
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])
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())
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())
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"])
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())
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))
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)
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)
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
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')
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))
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()
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
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
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
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)
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())
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)
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)
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)