def main() -> None: """Main.""" # parse simple SB2.1 file generated by elftosb.exe with open(f"{DATA_DIR}/test_output_sb_2_1_from_elftosb.sb2", "rb") as f: sb_file = f.read() img_obj21 = BootImageV21.parse(sb_file, kek=KEK_VALUE) print(img_obj21.info()) # parse SB2.1 file with OTFAD generated by elftosb.exe with open(f"{DATA_DIR}/otfad/test_output_sb_2_1_from_elftosb_OTFAD.sb2", "rb") as f: sb_file = f.read() img_obj21 = BootImageV21.parse(sb_file, kek=KEK_VALUE) print(img_obj21.info()) # Generate not signed SB2.0 raw image raw_data_sb20_base = gen_boot_image_20_base() # Parse raw image img_obj20 = BootImageV20.parse(raw_data_sb20_base, kek=KEK_VALUE) print(img_obj20.info()) # Generate signed SB2.0 raw image raw_data_sb20_signed = gen_boot_image_20() # Parse signed SB2.0 raw image img_obj20 = BootImageV20.parse(raw_data_sb20_signed, kek=KEK_VALUE) print(img_obj20.info()) # Generate SB21 raw image raw_data_sb21_signed = gen_boot_image_21() # Parse raw image img_obj21 = BootImageV21.parse(raw_data_sb21_signed, kek=KEK_VALUE) print(img_obj21.info())
def test_sb2_0_builder_validation(data_dir): """Validate exception from SB2.0 builder, if any required fields are not defined""" # create boot image boot_image = BootImageV20(True, kek=kek_value, product_version="1.0.0", component_version="1.0.0", build_number=1) # missing boot section with pytest.raises(SPSDKError): boot_image.export() for boot_sect in get_boot_sections(data_dir, False, SectionsContent.SIMPLE, 0): boot_image.add_boot_section(boot_sect) # missing certificate block with pytest.raises(SPSDKError): boot_image.export() boot_image.cert_block = gen_cert_block(data_dir, 2048) # missing private key with pytest.raises(SPSDKError): boot_image.export()
def build_sb(app: str, kek: bytes, address: int = 0) -> bytes: """Build a Secure Boot image. :param app: The application data :param kek: Key Encryption Key value :param address: Entry address for application :return: Serialized SB2.0 image """ with open(app, "rb") as f: boot_data = f.read() boot_section = BootSectionV2( 0, CmdErase(address, len(boot_data)), CmdLoad(address, boot_data), CmdReset(), hmac_count=10, ) boot_image = BootImageV20(signed=False, kek=kek) boot_image.add_boot_section(boot_section) print(boot_image.info()) return boot_image.export()
def test_sb20_parser(data_dir): """Test parser""" with open(os.path.join(data_dir, "SB2.0_Not_Signed.sb2"), "rb") as file: img_obj = BootImageV20.parse(file.read(), kek=kek_value) assert isinstance(img_obj, BootImageV20) # check info() produces something assert img_obj.info()
def gen_boot_image_20_base() -> bytes: """Generate SB2.0 image without signature.""" # create boot section boot_section = gen_boot_section() # create boot image boot_image = BootImageV20(signed=False, kek=KEK_VALUE) boot_image.add_boot_section(boot_section) # print image info # print(boot_image.info()) return boot_image.export()
def test_invalid_boot_image_v2(): with pytest.raises(SPSDKError, match="Invalid dek or mac"): BootImageV20(True, kek=kek_value, advanced_params=SBV2xAdvancedParams(dek=bytes(33), mac=bytes(33))) bimg = BootImageV20(False, kek=kek_value) with pytest.raises( SPSDKError, match="Certificate block cannot be used unless SB file is signed"): bimg.cert_block = CertBlockV2() bimg = BootImageV20(True, kek=bytes(31)) bimg.cert_block = None with pytest.raises(SPSDKError, match="Certification block not present"): bimg.raw_size_without_signature bimg = BootImageV20(True, kek=bytes(31)) with pytest.raises(SPSDKError, match="Certification block not present"): bimg.raw_size
def gen_boot_image_20() -> bytes: """Generate SB2.0 image with signature.""" # create boot section boot_section = gen_boot_section() adv_params = SBV2xAdvancedParams(dek=DEK_VALUE, mac=MAC_VALUE) # create boot image boot_image = BootImageV20( signed=True, kek=KEK_VALUE, product_version="1.0.0", component_version="1.0.0", build_number=1, advanced_params=adv_params, ) # add certificate block boot_image.cert_block = gen_cert_block() boot_image.private_key_pem_data = PRIVATE_KEY_PEM_DATA # add boot sections boot_image.add_boot_section(boot_section) # print image info # print(boot_image.info()) return boot_image.export()
def test_invalid_boot_image_v2_invalid_export(): bimg = BootImageV20(True, kek=bytes(31)) bimg._dek = bytes() with pytest.raises(SPSDKError, match="Invalid dek or mac"): bimg.export()
def test_invalid_boot_section_v2(): boot_img = BootImageV20(kek=kek_value, signed=False) with pytest.raises(SPSDKError): boot_img.add_boot_section(section=5)
def test_sb2x_builder( data_dir: str, sb_minor_ver: int, sign_bits: int, otfad: bool, sect_cont: SectionsContent, load_addr: int, ): """Test SB2.x builder in several use-cases :param data_dir: absolute path to load data :param sb_minor_ver: 0 or 1 to select SB2.0 or SB2.1 :param sign_bits: size of the signature in bits: 0 for unsigned; 2048 or 4096 :param sect_cont: content of the sections to test :param load_addr: load address for simple section """ assert sb_minor_ver in [0, 1] assert sign_bits in [0, 2048, 4096] signed = sign_bits != 0 if (sb_minor_ver == 1) or otfad: assert signed # this is hardcoded in the test; if not specified, random values will be used dek_value = b"\xA0" * 32 mac_value = b"\x0B" * 32 # this is hardcoded in the test; if not specified, current value will be used timestamp = datetime.fromtimestamp( int( datetime(2020, month=1, day=31, hour=0, tzinfo=timezone.utc).timestamp())) adv_params = SBV2xAdvancedParams(dek=dek_value, mac=mac_value, nonce=bytes(16), timestamp=timestamp) # create boot image if sb_minor_ver == 0: boot_image = BootImageV20( signed, kek=kek_value, product_version="1.0.0", component_version="1.0.0", build_number=1, # parameters fixed for test only, do not use in production advanced_params=adv_params, ) else: boot_image = BootImageV21( kek=kek_value, product_version="1.0.0", component_version="1.0.0", build_number=1, # parameters fixed for test only, do not use in production advanced_params=adv_params, flags=0x0008, ) if signed: boot_image.cert_block = gen_cert_block(data_dir, sign_bits) with open( os.path.join( data_dir, "sb2_x", "selfsign_privatekey_rsa" + str(sign_bits) + ".pem"), "rb", ) as keyf: key_data = keyf.read() boot_image.private_key_pem_data = key_data for sect in get_boot_sections(data_dir, otfad, sect_cont, load_addr): boot_image.add_boot_section(sect) result = boot_image.export(padding=bytes( 8)) # padding is added for tests only, do not use for production: # test raw_size assert len(result) == boot_image.raw_size # check that info() prints anything assert boot_image.info() sect_cont_str = SectionsContent.name(sect_cont) if otfad: mode = "otfad" elif signed: mode = "signed" + str(sign_bits) else: mode = "unsigned" extected_file_name = f"expected_sb2_{str(sb_minor_ver)}_{sect_cont_str}_{mode}.sb2" with open(os.path.join(data_dir, "sb2_x", extected_file_name), "rb") as f: expected = f.read() if result != expected: # if result does not match, save it for debugging with open( os.path.join( data_dir, "sb2_x", extected_file_name.replace("expected_", "generated_")), "wb", ) as f: f.write(result) assert result == expected