Example #1
0
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())
Example #2
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))
Example #3
0
def test_sb2_1_builder_validation(data_dir):
    """Validate exception from from SB2.1 builder, if any required fields are not defined"""
    # create boot image
    boot_image = BootImageV21(kek=kek_value, product_version='1.0.0', component_version='1.0.0', build_number=1)

    # missing boot section
    with pytest.raises(ValueError):
        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
    with pytest.raises(ValueError):
        boot_image.export()

    boot_image.cert_block = gen_cert_block(data_dir, 2048)
    # missing private key
    with pytest.raises(ValueError):
        boot_image.export()
Example #4
0
def gen_boot_image_21() -> bytes:
    """Generate SB2.1 image with signature."""
    # create boot section
    boot_section = gen_boot_section()
    # advanced parameters
    adv_params = SBV2xAdvancedParams(dek=DEK_VALUE, mac=MAC_VALUE)
    # create boot image
    boot_image = BootImageV21(KEK_VALUE,
                              boot_section,
                              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
    # print image info
    print(boot_image.info())

    return boot_image.export()
Example #5
0
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).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)

    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
Example #6
0
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_regs(
            data_dir,
            [
                (0x401301A8, 0x00001000),  # OTFAD CFG
                # OTFAD KEY INPUT - 12aaaaaabb34bbbbcccc56ccdddddd78
                (0x401301B0, 0xaaaaaa12),
                (0x401301B4, 0xbbbb34bb),
                (0x401301B8, 0xcc56cccc),
                (0x401301BC, 0x78dddddd),
            ])
        write_shadow_regs(
            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))

    # 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)

    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=bytes.fromhex('063040C0')),
        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)
Example #7
0
def test_sb_otfad_keystore(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 stored in KEYSTORE.

    :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_regs(
            data_dir,
            [
                (0x40130194, 0x00000080),  # BOOT_CFG[5]: USE_PUF = 1
                (0x401301A8, 0x00001000),  # OTFAD CFG
                (0x40130180, 0x00000010 +
                 secure_boot_en),  # BOOT_CFG[0]: DEFAULT_ISP = 1(USB)
            ])

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

    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))

    # create SB file 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)

    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)
    with open(os.path.join(data_dir, KEYSTORE_SUBDIR, 'OTFADKek_PUF.txt'),
              'r') as f:
        otfad_kek = f.readline()

    # create boot section 0
    boot_section = BootSectionV2(
        0,
        # configure external FLASH
        CmdFill(address=0x10C000, pattern=bytes.fromhex('063040C0')),
        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_keystore.sb', dbg_info,
                  TEST_IMG_CONTENT)
    write_sb(data_dir, image_name + '_otfad_keystore.sb', sb_file, key_store)
Example #8
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))