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_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 = 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_otp.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 get_keystore(data_dir: str) -> KeyStore: """Return key-store for current processor See description of `UPDATE_KEYSTORE` and `gen_keystore` for more details :param data_dir: absolute path of directory with data :return: instance of key-store class with key-store binary data """ if UPDATE_KEYSTORE: key_store_bin = generate_keystore(data_dir) # generate new key-store for current processor else: # load keystore with HMAC user key key_store_path = os.path.join(data_dir, KEYSTORE_SUBDIR, KEY_STORE_FILE_NAME) with open(key_store_path, "rb") as f: key_store_bin = f.read() return KeyStore(KeySourceType.KEYSTORE, key_store_bin)
def send_sb_via_usb_into_processor(sb_data: bytes, key_store: KeyStore) -> None: """ Send SB file into processor :param sb_data: SB file to be sent :param key_store: key-store used for SB file :raise ConnectionError: if USB connection with processor's boot-loader cannot be established """ if TEST_IMG_CONTENT: # this function communicates with HW board, it cannot be used in test mode return mboot = open_mboot() if key_store.key_source == KeySourceType.KEYSTORE: # configure keystore into processor # Mind key store is device specific, it is unique for each piece chip # blhost -u 0x1FC9,0x20 -- key-provisioning write_key_store "key_store\key_store_spsdk.bin" assert mboot.kp_write_key_store(key_store.export()) # write SB assert mboot.receive_sb_file(sb_data) mboot.close()
def test_sb_otfad_otp(data_dir: str, subdir: str, image_name: str, secure: bool) -> None: """Test creation of SB file for RT5xx with OTFAD encrypted image. SBKEK Key for SB file is derived from master key in OTP. :param data_dir: absolute path of the directory with data files for the test :param image_name: file name of the signed image WITHOUT file extension :param secure: whether security should be enabled """ if not TEST_IMG_CONTENT: secure_boot_en = 0x900000 if secure else 0 # BOOT_CFG[0]: SECURE_BOOT_EN=? write_shadow_regis( data_dir, [ (0x401301A8, 0x00001000), # OTFAD CFG # OTFAD KEY INPUT - 12aaaaaabb34bbbbcccc56ccdddddd78 (0x401301B0, 0xAAAAAA12), (0x401301B4, 0xBBBB34BB), (0x401301B8, 0xCC56CCCC), (0x401301BC, 0x78DDDDDD), ], ) write_shadow_regis( data_dir, [ # MASTER KEY - 000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff (0x401301C0, 0xCCDDEEFF), (0x401301C4, 0x8899AABB), (0x401301C8, 0x44556677), (0x401301CC, 0x00112233), (0x401301D0, 0x0C0D0E0F), (0x401301D4, 0x08090A0B), (0x401301D8, 0x04050607), (0x401301DC, 0x00010203), # BOOT_CFG[0]: DEFAULT_ISP = 1(USB) (0x40130180, 0x00000010 + secure_boot_en), ], ) sbkek = KeyStore.derive_sb_kek_key(bytes.fromhex(MASTER_KEY)) otfad_kek = KeyStore.derive_otfad_kek_key( bytes.fromhex(MASTER_KEY), bytes.fromhex("12aaaaaabb34bbbbcccc56ccdddddd78")) key_store = get_keystore(data_dir) adv_params = SBV2xAdvancedParams( dek=b"\xA0" * 32, mac=b"\x0B" * 32, nonce=bytes(16), timestamp=datetime(2020, month=1, day=31, hour=0, tzinfo=timezone.utc), ) # 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, flags=0x0008, ) # 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) otfad = Otfad() # keys used to encrypt image, for RT5xx always define 4 key blobs!! key = bytes.fromhex("B1A0C56AF31E98CD6936A79D9E6F829D") counter = bytes.fromhex("5689fab8b4bfb264") otfad.add_key_blob( KeyBlob(0x8001000, 0x80FFFFF, key, counter, zero_fill=bytes(4), crc=bytes( 4))) # zero_fill and crc should be used only for testing ! # to use random keys: otfad.add_key_blob(KeyBlob(0x8001000, 0x80FFFFF)) otfad.add_key_blob( KeyBlob(0x8FFD000, 0x8FFDFFF, key, counter, zero_fill=bytes(4), crc=bytes( 4))) # zero_fill and crc should be used only for testing ! otfad.add_key_blob( KeyBlob(0x8FFE000, 0x8FFEFFF, key, counter, zero_fill=bytes(4), crc=bytes( 4))) # zero_fill and crc should be used only for testing ! otfad.add_key_blob( KeyBlob(0x8FFF000, 0x8FFFFFF, key, counter, zero_fill=bytes(4), crc=bytes( 4))) # zero_fill and crc should be used only for testing ! encr_image_data = otfad.encrypt_image(plain_image_data, 0x8001000, False) # create boot section 0 boot_section = BootSectionV2( 0, # configure external FLASH CmdFill(address=0x10C000, pattern=int("063040C0", 16)), CmdMemEnable(0x10C000, 4, ExtMemId.FLEX_SPI_NOR), # erase the FLASH CmdErase(address=0x8000000, length=0x10000), # load key blobs allowing th decrypt the image CmdLoad(address=0x8000000, data=otfad.encrypt_key_blobs(kek=otfad_kek)), # load FCB data CmdLoad(address=0x8000400, data=fcb_data), # load key-store CmdLoad(address=0x8000800, data=key_store.export()), # load encrypted image CmdLoad(address=0x8001000, data=encr_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 + "_otfad_otp.sb", dbg_info, TEST_IMG_CONTENT) write_sb(data_dir, image_name + "_otfad_otp.sb", sb_file, key_store)