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 = 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_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 = MasterBootImage(app=unsigned_img, image_type=MasterBootImageType.SIGNED_RAM_IMAGE, load_addr=ram_addr, key_store=keystore, hmac_key=MASTER_KEY, trust_zone=TrustZone.disabled(), cert_block=cert_block, priv_key_pem_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 test_encrypted_random_ctr_single_certificate_no_tz(data_dir): """Test encrypted image with random counter init vector""" with open(os.path.join(data_dir, 'testfffffff.bin'), "rb") as f: org_data = f.read() user_key = 'E39FD7AB61AE6DDDA37158A0FC3008C6D61100A03C7516EA1BE55A39F546BAD5' key_store = KeyStore(KeySourceType.KEYSTORE, None) cert_block = certificate_block(data_dir, ['selfsign_2048_v3.der.crt']) priv_key_pem_data = _load_private_key(data_dir, 'selfsign_privatekey_rsa2048.pem') mbi = MasterBootImage(app=org_data, image_type=MasterBootImageType.ENCRYPTED_RAM_IMAGE, load_addr=0x12345678, trust_zone=TrustZone.disabled(), cert_block=cert_block, priv_key_pem_data=priv_key_pem_data, hmac_key=user_key, key_store=key_store) assert mbi.export() assert mbi.info()
def test_signed_xip_multiple_certificates_invalid_input(data_dir): """Test invalid input for multiple certificates""" # indexed certificate is not specified der_file_names = ['selfsign_4096_v3.der.crt', 'selfsign_3072_v3.der.crt', 'selfsign_2048_v3.der.crt'] with pytest.raises(IndexError): certificate_block(data_dir, der_file_names, 3) # indexed certificate is not specified der_file_names = ['selfsign_4096_v3.der.crt', None, 'selfsign_3072_v3.der.crt', 'selfsign_2048_v3.der.crt'] with pytest.raises(ValueError): certificate_block(data_dir, der_file_names, 1) # public key in certificate and private key does not match der_file_names = ['selfsign_4096_v3.der.crt'] cert_block = certificate_block(data_dir, der_file_names, 0) priv_key_pem_data = _load_private_key(data_dir, 'selfsign_privatekey_rsa2048.pem') with pytest.raises(ValueError): MasterBootImage(app=bytes(range(128)), load_addr=0, image_type=MasterBootImageType.SIGNED_XIP_IMAGE, trust_zone=TrustZone.disabled(), cert_block=cert_block, priv_key_pem_data=priv_key_pem_data).export() # chain of certificates does not match der_file_names = ['selfsign_4096_v3.der.crt'] chain_certificates = ['ch3_crt2_v3.der.crt'] with pytest.raises(ValueError): certificate_block(data_dir, der_file_names, 0, chain_certificates)
def test_multiple_images_with_relocation_table(data_dir): """Test image that contains multiple binary images and relocation table :param data_dir: absolute path, where test data are located """ with open(os.path.join(data_dir, 'multicore', "testfffffff.bin"), "rb") as f: img_data = f.read() with open(os.path.join(data_dir, 'multicore', "normal_boot.bin"), "rb") as f: img1_data = f.read() with open(os.path.join(data_dir, 'multicore', "special_boot.bin"), "rb") as f: img2_data = f.read() with open(os.path.join(data_dir, 'multicore', "rt5xxA0.json"), "rb") as f: trust_zone_data = json.loads(f.read())['trustZonePreset'] table = MultipleImageTable() table.add_entry(MultipleImageEntry(img1_data, 0x80000)) table.add_entry(MultipleImageEntry(img2_data, 0x80600)) mbi = MasterBootImage(app=img_data, app_table=table, load_addr=0, image_type=MasterBootImageType.CRC_RAM_IMAGE, trust_zone=TrustZone.custom('rt5xx', trust_zone_data)) assert _compare_image(mbi, os.path.join(data_dir, 'multicore'), 'expected_output.bin')
def test_signed_xip_certificates_chain_no_tz(data_dir, der_certificates, chain_certificates, priv_key, expected_mbi): """Test signed image with multiple certificates, different key length :param data_dir: absolute path, where test data are located :param der_certificates: list of filenames of der root certificates :param chain_certificates: list of filenames of der cerificates :param priv_key: private key filename :param expected_mbi: filename of expected bootable image """ with open(os.path.join(data_dir, 'testfffffff.bin'), "rb") as f: org_data = f.read() # create certification block cert_block = certificate_block(data_dir, der_certificates, 0, chain_certificates) priv_key_pem_data = _load_private_key(data_dir, priv_key) mbi = MasterBootImage(app=org_data, load_addr=0, image_type=MasterBootImageType.SIGNED_XIP_IMAGE, trust_zone=TrustZone.disabled(), cert_block=cert_block, priv_key_pem_data=priv_key_pem_data) assert _compare_image(mbi, data_dir, expected_mbi)
def test_signed_ram_single_certificate_no_tz(data_dir, user_key, key_store_filename, expected_mbi): """Test non-XIP signed image with single certificate :param data_dir: absolute path, where test data are located """ with open(os.path.join(data_dir, 'testfffffff.bin'), "rb") as f: org_data = f.read() # create certification block cert_block = certificate_block(data_dir, ['selfsign_2048_v3.der.crt']) priv_key_pem_data = _load_private_key(data_dir, 'selfsign_privatekey_rsa2048.pem') key_store = None if key_store_filename: with open(os.path.join(data_dir, key_store_filename), "rb") as f: key_store_bin = f.read() key_store = KeyStore(KeySourceType.KEYSTORE, key_store_bin) mbi = MasterBootImage(app=org_data, image_type=MasterBootImageType.SIGNED_RAM_IMAGE, load_addr=0x12345678, trust_zone=TrustZone.disabled(), cert_block=cert_block, priv_key_pem_data=priv_key_pem_data, hmac_key=user_key, key_store=key_store) assert _compare_image(mbi, data_dir, expected_mbi)
def test_encrypted_ram_single_certificate_no_tz(data_dir, keysource: KeySourceType, keystore_fn: Optional[str], ctr_iv: str, expected_mbi: str): """Test encrypted image with fixed counter init vector""" with open(os.path.join(data_dir, 'testfffffff.bin'), "rb") as f: org_data = f.read() user_key = 'E39FD7AB61AE6DDDA37158A0FC3008C6D61100A03C7516EA1BE55A39F546BAD5' key_store_bin = None if keystore_fn: with open(os.path.join(data_dir, keystore_fn), "rb") as f: key_store_bin = f.read() key_store = KeyStore(keysource, key_store_bin) ctr_init_vector = bytes.fromhex(ctr_iv) # create certification block cert_block = certificate_block(data_dir, ['selfsign_2048_v3.der.crt']) priv_key_pem_data = _load_private_key(data_dir, 'selfsign_privatekey_rsa2048.pem') mbi = MasterBootImage(app=org_data, image_type=MasterBootImageType.ENCRYPTED_RAM_IMAGE, load_addr=0x12345678, trust_zone=TrustZone.disabled(), cert_block=cert_block, priv_key_pem_data=priv_key_pem_data, hmac_key=user_key, key_store=key_store, ctr_init_vector=ctr_init_vector) assert _compare_image(mbi, data_dir, expected_mbi)
def test_xip_crc(data_dir: str, image_file_name: str) -> None: """ Create image with CRC :param data_dir: absolute path with data files :param image_file_name: name of the input image file (including extension) """ assert image_file_name.endswith('_unsigned.bin') path = os.path.join(data_dir, INPUT_IMAGES_SUBDIR, image_file_name) unsigned_image = load_binary(path) mbi = MasterBootImage(app=unsigned_image, load_addr=0x8001000, image_type=MasterBootImageType.CRC_XIP_IMAGE) out_image_file_name = image_file_name.replace('_unsigned.bin', '_crc.bin') write_image(data_dir, out_image_file_name, mbi.export())
def test_ram_crc(data_dir: str, image_file_name: str, ram_addr: int) -> None: """ Create image with CRC :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 """ assert image_file_name.endswith('_unsigned.bin') path = os.path.join(data_dir, INPUT_IMAGES_SUBDIR, image_file_name) unsigned_image = load_binary(path) mbi = MasterBootImage(app=unsigned_image, load_addr=ram_addr, image_type=MasterBootImageType.CRC_RAM_IMAGE) out_image_file_name = image_file_name.replace('_unsigned.bin', '_crc.bin') write_image(data_dir, out_image_file_name, mbi.export())
def _compare_image(mbi: MasterBootImage, data_dir: str, expected_mbi_filename: str) -> bool: """Compare generated image with expected image :param mbi: master boot image instance configured to generate image data :param expected_mbi_filename: file name of expected image :return: True if data are same; False otherwise """ generated_image = mbi.export() with open(os.path.join(data_dir, expected_mbi_filename), "rb") as f: expected_data = f.read() if generated_image != expected_data: with open(os.path.join(data_dir, expected_mbi_filename + ".created"), "wb") as f: f.write(generated_image) return False assert mbi.export() == expected_data # check additional call still generates the same data return True
def test_xip_signed(data_dir: str, image_file_name: str) -> None: """Create signed XIP image :param data_dir: absolute path with data files :param image_file_name: name of the input image file (including extension) """ # 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) cert_block, priv_key_pem_data = create_cert_block(data_dir) mbi = MasterBootImage(app=unsigned_img, image_type=MasterBootImageType.SIGNED_XIP_IMAGE, load_addr=0x8001000, cert_block=cert_block, priv_key_pem_data=priv_key_pem_data) out_image_file_name = image_file_name.replace('_unsigned.bin', '_signed.bin') write_image(data_dir, out_image_file_name, mbi.export())
def test_plain_xip_crc_default_tz(data_dir, input_img, expected_mbi): """Test plain image with CRC and default TZ-M :param data_dir: absolute path, where test data are located :param input_img: file name of input image (binary) :param expected_mbi: file name of MBI image file with expected data """ with open(os.path.join(data_dir, input_img), "rb") as f: org_data = f.read() mbi = MasterBootImage(app=org_data, load_addr=0, image_type=MasterBootImageType.CRC_XIP_IMAGE, trust_zone=TrustZone.enabled()) assert _compare_image(mbi, data_dir, expected_mbi)
def test_base_info(data_dir): """Basic test for MasterBootImage - information """ # plain image mbi = MasterBootImage(app=bytes(range(64)), load_addr=0, enable_hw_user_mode_keys=True) output = mbi.info() repr_strings = [ "Master Boot Image", "Image type", "Image length", "TrustZone", 'HW user mode keys' ] for req_string in repr_strings: assert req_string in output, f'string {req_string} is not in the output: {output}' # CRC image mbi = MasterBootImage(app=bytes(range(64)), image_type=MasterBootImageType.CRC_RAM_IMAGE, load_addr=0x1000) output = mbi.info() repr_strings = [ "Master Boot Image", "Image type", "Image length", "TrustZone" ] for req_string in repr_strings: assert req_string in output, f'string {req_string} is not in the output: {output}' # signed image priv_key_pem_data = _load_private_key(data_dir, 'private_rsa4096.pem') cert_block = certificate_block( data_dir, ['selfsign_4096_v3.der.crt', 'selfsign_3072_v3.der.crt'], 0) mbi = MasterBootImage(app=bytes(range(64)), load_addr=0x12345678, image_type=MasterBootImageType.SIGNED_XIP_IMAGE, trust_zone=TrustZone.custom( "lpc55xx", {"MPU Control Register.(cm33_mpu_ctrl)": "0x0"}), cert_block=cert_block, priv_key_pem_data=priv_key_pem_data) output = mbi.info() repr_strings = [ "Master Boot Image", "Image type", "Image length", "TrustZone" ] for req_string in repr_strings: assert req_string in output, f'string {req_string} is not in the output: {output}'
def test_signed_xip_single_certificate_no_tz(data_dir, priv_key, der_certificate, expected_mbi): """Test signed XIP image with single certificate, different key length :param data_dir: absolute path, where test data are located :param priv_key: filename of private key used for signing :param der_certificate: filename of corresponding certificate in DER format :param expected_mbi: filename of expected bootable image """ with open(os.path.join(data_dir, 'testfffffff.bin'), "rb") as f: org_data = f.read() # create certification block cert_block = certificate_block(data_dir, [der_certificate]) priv_key_pem_data = _load_private_key(data_dir, priv_key) mbi = MasterBootImage(app=org_data, load_addr=0, image_type=MasterBootImageType.SIGNED_XIP_IMAGE, trust_zone=TrustZone.disabled(), cert_block=cert_block, priv_key_pem_data=priv_key_pem_data) assert _compare_image(mbi, data_dir, expected_mbi)
def test_plain_xip_crc_custom_tz(data_dir, input_img, tz_config, family, expected_mbi): """Test plain image with CRC and custom TZ-M :param data_dir: absolute path, where test data are located :param input_img: file name of input image (binary) :param tz_config: file name of trust-zone configuration JSON file :param family: identification of the processor for conversion of trust-zone data :param expected_mbi: file name of MBI image file with expected data """ with open(os.path.join(data_dir, input_img), "rb") as f: org_data = f.read() with open(os.path.join(data_dir, expected_mbi), "rb") as f: expected_data = f.read() with open(os.path.join(data_dir, tz_config)) as f: tz_presets = json.load(f)["trustZonePreset"] mbi = MasterBootImage(app=org_data, load_addr=0, image_type=MasterBootImageType.CRC_XIP_IMAGE, trust_zone=TrustZone(family=family, customizations=tz_presets)) assert _compare_image(mbi, data_dir, expected_mbi)
def test_invalid_master_boot_image_params(data_dir): with pytest.raises(TypeError): # noinspection PyTypeChecker MasterBootImage(app=5) # load_addr must not be negative with pytest.raises(AssertionError): MasterBootImage(app=bytes(range(64)), load_addr=-1, image_type=MasterBootImageType.CRC_XIP_IMAGE) # certificate block is supported for signed images with pytest.raises(ValueError): MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.SIGNED_RAM_IMAGE) with pytest.raises(ValueError): MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.SIGNED_XIP_IMAGE) # hmac_key must be provided for load-to-ram image cert_block = certificate_block(data_dir, ['selfsign_2048_v3.der.crt']) priv_key_pem_data = _load_private_key(data_dir, 'selfsign_privatekey_rsa2048.pem') with pytest.raises(ValueError): MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.SIGNED_RAM_IMAGE, cert_block=cert_block, priv_key_pem_data=priv_key_pem_data) with pytest.raises(ValueError): MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.SIGNED_RAM_IMAGE, cert_block=cert_block, priv_key_pem_data=priv_key_pem_data, key_store=KeyStore(KeySourceType.OTP)) with pytest.raises(ValueError): MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.SIGNED_RAM_IMAGE, cert_block=cert_block, priv_key_pem_data=priv_key_pem_data, key_store=KeyStore(KeySourceType.KEYSTORE)) # hmac_key (or key_store) cannot be provided for XIP image with pytest.raises(ValueError): MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.SIGNED_XIP_IMAGE, cert_block=cert_block, priv_key_pem_data=priv_key_pem_data, hmac_key=bytes(range(32))) with pytest.raises(ValueError): MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.SIGNED_XIP_IMAGE, cert_block=cert_block, priv_key_pem_data=priv_key_pem_data, key_store=KeyStore(KeySourceType.KEYSTORE)) # app_table can be specified only for RAM images with pytest.raises(ValueError): app_table = MultipleImageTable() MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.CRC_XIP_IMAGE, app_table=app_table) # app_table is empty with pytest.raises(ValueError): app_table = MultipleImageTable() MasterBootImage(app=bytes(range(64)), load_addr=0, image_type=MasterBootImageType.CRC_RAM_IMAGE, app_table=app_table) # error if image len is not enough with pytest.raises(ValueError): MasterBootImage(app=bytes(range(32)), load_addr=0).export()