Beispiel #1
0
def test_load_cmd_invalid_parse_crc():
    cmd = CmdLoad(address=100, data=b"\x00" * 100)
    data = cmd.export()
    with pytest.raises(SPSDKError, match="Invalid CRC in the command header"):
        CmdLoad.parse(
            data=
            b"Q\x02\x00\x00d\x00\x00\x00p\x00\x00\x00\x02z\xa7\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xd1a\x13<\xf5 \x9cP\xb8\x00\x00"
        )
Beispiel #2
0
def test_load_cmd_invalid_crc():
    cmd = CmdLoad(address=100, data=b"\x00" * 100)
    valid_data = cmd.export()
    invalid_data = valid_data
    invalid_data = bytearray(invalid_data)
    invalid_data[17:112] = bytearray(112)
    with pytest.raises(SPSDKError):
        cmd.parse(invalid_data)
Beispiel #3
0
def test_load_cmd():
    cmd = CmdLoad(address=100, data=b"\x00" * 100)
    assert cmd.address == 100
    assert cmd.data == bytearray([0] * 100)
    assert cmd.info()

    cmd.data = cmd.data + b"\x10"
    assert len(cmd.data) == 101

    data = cmd.export()
    assert len(data) == 128
    assert len(data) == cmd.raw_size

    cmd_parsed = parse_command(data)
    assert cmd == cmd_parsed
Beispiel #4
0
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()
Beispiel #5
0
def _load(cmd_args: dict) -> CmdLoad:
    """Returns a CmdLoad object initialized based on cmd_args.

    :param cmd_args: dictionary holding path to file or values and address
    :raises SPSDKError: If dict doesn't contain 'file' or 'values' key
    :return: CmdLoad object
    """
    address = cmd_args["address"]
    # general non-authenticated load command
    if cmd_args.get("file"):
        data = load_binary(cmd_args["file"])
        return CmdLoad(address=address, data=data)
    if cmd_args.get("values"):
        values = [int(s, 16) for s in cmd_args["values"].split(",")]
        data = struct.pack(f"<{len(values)}L", *values)
        return CmdLoad(address=address, data=data)
    raise SPSDKError(f"Unsupported LOAD command args: {cmd_args}")
Beispiel #6
0
def _encrypt(cmd_args: dict) -> CmdLoad:
    """Returns a CmdLoad object initialized based on cmd_args.

    Encrypt holds an ID, which is a reference to keyblob to be used for
    encryption. So the encrypt command requires a list of keyblobs, the keyblob
    ID and load command.

    e.g.
    encrypt (0){
        load myImage > 0x0810000;
    }

    :param cmd_args: dictionary holding list of keyblobs, keyblob ID and load dict
    :raises SPSDKError: If keyblob to be used is not in the list or is invalid
    :return: CmdLoad object
    """
    keyblob_id = cmd_args["keyblob_id"]
    keyblobs = cmd_args.get("keyblobs", [])
    load_dict = cmd_args.get("load", {})

    address = load_dict["address"]

    if load_dict.get("file"):
        data = load_binary(load_dict["file"])
    if load_dict.get("values"):
        values = [int(s, 16) for s in load_dict["values"].split(",")]
        data = struct.pack(f"<{len(values)}L", *values)

    try:
        valid_keyblob = _validate_keyblob(keyblobs, keyblob_id)
    except SPSDKError as exc:
        raise SPSDKError(f"Invalid key blob {str(exc)}") from exc

    if valid_keyblob is None:
        raise SPSDKError(f"Missing keyblob {keyblob_id} for encryption.")

    start_addr = valid_keyblob["keyblob_content"][0]["start"]
    end_addr = valid_keyblob["keyblob_content"][0]["end"]
    key = bytes.fromhex(valid_keyblob["keyblob_content"][0]["key"])
    counter = bytes.fromhex(valid_keyblob["keyblob_content"][0]["counter"])
    byte_swap = valid_keyblob["keyblob_content"][0].get("byte_swap", False)

    keyblob = KeyBlob(start_addr=start_addr,
                      end_addr=end_addr,
                      key=key,
                      counter_iv=counter)

    encoded_data = keyblob.encrypt_image(base_address=address,
                                         data=data,
                                         byte_swap=byte_swap)

    return CmdLoad(address, encoded_data)
Beispiel #7
0
def gen_boot_section() -> BootSectionV2:
    """Generate a Boot Section withput encryption."""
    with open(f"{DATA_DIR}/boot_image.bin", "rb") as boot_image_file:
        boot_data = boot_image_file.read()

    boot_section = BootSectionV2(
        0,
        CmdErase(address=0, length=100000),
        CmdLoad(address=0, data=boot_data),
        CmdReset(),
        hmac_count=10,
    )

    return boot_section
Beispiel #8
0
def gen_boot_section_otfad() -> BootSectionV2:
    """Generate a Boot Section with content encrypted by OTFAD.

    :raises SPSDKError: When length of key blobs is not 256
    """
    with open(f"{DATA_DIR}/boot_image.bin", "rb") as boot_image_file:
        boot_data = boot_image_file.read()

    otfad = Otfad()
    key = bytes.fromhex("B1A0C56AF31E98CD6936A79D9E6F829D")
    counter = bytes.fromhex("5689fab8b4bfb264")
    otfad.add_key_blob(
        KeyBlob(
            0x08001000,
            0x0800F3FF,
            key,
            counter,
            zero_fill=bytes(4),
            crc=bytes(4),
        ))  # zero_fill and crc should be used only for testing !
    enc_image = otfad.encrypt_image(boot_data, 0x08001000, True)
    key_blobs = otfad.encrypt_key_blobs(
        kek=bytes.fromhex("50F66BB4F23B855DCD8FEFC0DA59E963"))
    if len(key_blobs) != 256:
        raise SPSDKError("Length of key blobs is not 256")

    boot_section = BootSectionV2(
        0,
        CmdErase(address=0x08001000, length=0x0800F000 - 0x08001000),
        CmdLoad(address=0x08001000, data=enc_image),
        CmdLoad(address=0x08000000, data=key_blobs),
        CmdReset(),
        hmac_count=10,
    )

    return boot_section
Beispiel #9
0
def test_boot_section_v2():
    boot_section = BootSectionV2(0, CmdErase(address=0, length=100000),
                                 CmdLoad(address=0, data=b"0123456789"),
                                 CmdReset())

    assert boot_section.uid == 0
    assert not boot_section.is_last
    assert boot_section.hmac_count == 1
    assert boot_section.raw_size == 144

    dek = crypto_backend().random_bytes(32)
    mac = crypto_backend().random_bytes(32)
    nonce = crypto_backend().random_bytes(16)
    data = boot_section.export(dek, mac, Counter(nonce))
    assert data
    assert BootSectionV2.parse(data, 0, False, dek, mac, Counter(nonce))

    with pytest.raises(SPSDKError,
                       match="Invalid type of dek, should be bytes"):
        BootSectionV2.parse(data=data,
                            offset=0,
                            plain_sect=False,
                            dek=4,
                            mac=mac,
                            counter=Counter(nonce))

    with pytest.raises(SPSDKError,
                       match="Invalid type of mac, should be bytes"):
        BootSectionV2.parse(data=data,
                            offset=0,
                            plain_sect=False,
                            dek=dek,
                            mac=4,
                            counter=Counter(nonce))

    with pytest.raises(SPSDKError, match="Invalid type of counter"):
        BootSectionV2.parse(data=data,
                            offset=0,
                            plain_sect=False,
                            dek=dek,
                            mac=mac,
                            counter=5)

    with pytest.raises(SPSDKError):
        assert BootSectionV2.parse(data, 0, False, dek,
                                   crypto_backend().random_bytes(32),
                                   Counter(nonce))
Beispiel #10
0
def test_boot_section_v2_invalid_export():
    boot_section = BootSectionV2(0, CmdErase(address=0, length=100000),
                                 CmdLoad(address=0, data=b"0123456789"),
                                 CmdReset())
    dek = 32
    mac = 4
    nonce = crypto_backend().random_bytes(16)
    with pytest.raises(SPSDKError,
                       match="Invalid type of dek, should be bytes"):
        boot_section.export(dek, mac, Counter(nonce))
    dek = crypto_backend().random_bytes(32)
    with pytest.raises(SPSDKError,
                       match="Invalid type of mac, should be bytes"):
        boot_section.export(dek, mac, Counter(nonce))
    counter = 5
    mac = crypto_backend().random_bytes(32)
    with pytest.raises(SPSDKError, match="Invalid type of counter"):
        boot_section.export(dek, mac, counter)
Beispiel #11
0
def _keywrap(cmd_args: dict) -> CmdLoad:
    """Returns a CmdLoad object initialized based on cmd_args.

    Keywrap holds keyblob ID to be encoded by a value stored in load command and
    stored to address defined in the load command.

    e.g.
    keywrap (0) {
        load {{ 00000000 }} > 0x08000000;
    }

    :param cmd_args: dictionary holding list of keyblobs, keyblob ID and load dict
    :raises SPSDKError: If keyblob to be used is not in the list or is invalid
    :return: CmdLoad object
    """
    # iterate over keyblobs
    keyblobs = cmd_args.get("keyblobs", None)
    keyblob_id = cmd_args.get("keyblob_id", None)
    load_info = cmd_args.get("load", None)

    address = load_info.get("address")
    otfad_key = load_info.get("values")

    try:
        valid_keyblob = _validate_keyblob(keyblobs, keyblob_id)
    except SPSDKError as exc:
        raise SPSDKError(f" Key blob validation failed: {str(exc)}") from exc
    if valid_keyblob is None:
        raise SPSDKError(f"Missing keyblob {keyblob_id} for given keywrap")

    start_addr = valid_keyblob["keyblob_content"][0]["start"]
    end_addr = valid_keyblob["keyblob_content"][0]["end"]
    key = bytes.fromhex(valid_keyblob["keyblob_content"][0]["key"])
    counter = bytes.fromhex(valid_keyblob["keyblob_content"][0]["counter"])

    blob = KeyBlob(start_addr=start_addr,
                   end_addr=end_addr,
                   key=key,
                   counter_iv=counter)

    encoded_keyblob = blob.export(kek=otfad_key)
    print("creating wrapped keyblob")

    return CmdLoad(address=address, data=encoded_keyblob)
Beispiel #12
0
def get_boot_sections(data_dir: str, otfad: bool, sect_cont: SectionsContent,
                      load_addr: int) -> List[BootSectionV2]:
    """Create list of boot sections for SB 2.x file

    :param data_dir: absolute path to load boot image
    :param otfad: True to encrypt section with OTFAD; False otherwise
    :param sect_cont: sections content to test
    :param load_addr: address where to load the image (for simple section)
    :return:
    """
    result = list()

    # load input image (binary)
    with open(os.path.join(data_dir, "sb2_x", "boot_image.bin"), "rb") as f:
        plain_image = f.read()

    # OTFAD
    key_blobs_data = list()
    if otfad:
        otfad = Otfad()
        # key blob 0
        key = bytes.fromhex("B1A0C56AF31E98CD6936A79D9E6F829D")
        counter = bytes.fromhex("5689fab8b4bfb264")
        key_blob = KeyBlob(
            0x08001000,
            0x0800F3FF,
            key,
            counter,
            zero_fill=bytes(4),
            crc=bytes(
                4))  # zero_fill and crc should be used only for testing !
        otfad.add_key_blob(key_blob)
        key_blobs_data = list()
        key_blobs_data.append(
            key_blob.export(
                kek=bytes.fromhex("50F66BB4F23B855DCD8FEFC0DA59E963")))
        # verify `otfad.encrypt_key_blobs` returns the same
        assert (key_blobs_data[0] == otfad.encrypt_key_blobs(
            kek=bytes.fromhex("50F66BB4F23B855DCD8FEFC0DA59E963"))[:64])
        # key blob 1
        if sect_cont == SectionsContent.ADVANCED:
            key = bytes.fromhex("12345678901234567890123456789012")
            counter = bytes.fromhex("0011223344556677")
            key_blob1 = KeyBlob(
                0x08010000,
                0x0801F3FF,
                key,
                counter,
                zero_fill=bytes(4),
                crc=bytes(
                    4))  # zero_fill and crc should be used only for testing !
            otfad.add_key_blob(key_blob1)
            key_blobs_data.append(
                key_blob1.export(
                    kek=bytes.fromhex("0123456789ABCDEF0123456789ABCDEF")))
        # encrypted image
        encr_image = otfad.encrypt_image(plain_image, load_addr, True)
    else:
        encr_image = plain_image

    if sect_cont == SectionsContent.ADVANCED:
        # add boot sections 1 - advanced
        boot_section2 = BootSectionV2(
            1,
            CmdErase(address=0, length=0x2800),
            CmdLoad(address=0x10000000, data=plain_image),
            CmdLoad(address=0x20000000, data=plain_image),
            CmdCall(0xFFFF0000),
            CmdJump(0x12345678),
            CmdReset(),
            hmac_count=5,
        )
        assert boot_section2.uid == 1
        result.append(boot_section2)

    # create boot section 0
    if sect_cont == SectionsContent.NEW_CMDS:
        boot_section0 = BootSectionV2(
            0,
            CmdVersionCheck(VersionCheckType.SECURE_VERSION, 0x16),
            CmdVersionCheck(VersionCheckType.NON_SECURE_VERSION, 15263),
            CmdErase(address=0, length=0x2800),
            CmdLoad(address=load_addr, data=encr_image),
            CmdKeyStoreBackup(0x12345678, 3),
            CmdKeyStoreRestore(0x12345678, 3),
            hmac_count=1,
        )
    else:
        boot_section0 = BootSectionV2(
            0,
            CmdErase(address=0, length=0x2800),
            CmdLoad(address=load_addr, data=encr_image),
            hmac_count=10,
        )
    for index, key_blob_data in enumerate(key_blobs_data):
        key_blob_aligned = align_block(
            key_blob_data,
            256)  # it seems key-blob from elf-to-sb is aligned to 256
        boot_section0.append(
            CmdLoad(address=0x8000000 + 0x100 * index, data=key_blob_aligned))
    boot_section0.append(CmdReset())
    result.append(boot_section0)

    return result
Beispiel #13
0
def test_load_cmd_invalid_address():
    cmd = CmdLoad(address=100, data=b"\x00" * 100)
    with pytest.raises(SPSDKError, match="Incorrect address"):
        cmd.address = 0xFFFFFFFFD
Beispiel #14
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_regis(
            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, hour=0, tzinfo=timezone.utc),
    )

    # 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,
        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)
    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=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_keystore.sb", dbg_info,
                  TEST_IMG_CONTENT)
    write_sb(data_dir, image_name + "_otfad_keystore.sb", sb_file, key_store)
Beispiel #15
0
def test_sb_signed_encr_keystore(data_dir: str, subdir: str,
                                 image_name: str) -> None:
    """Test creation of SB file for RT5xx with signed or 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 or encrypted image WITHOUT file extension
    """
    if not TEST_IMG_CONTENT:
        write_shadow_regis(
            data_dir,
            [
                (0x40130194, 0x00000080),  # BOOT_CFG[5]: USE_PUF = 1
                (
                    0x40130180,
                    0x00900010,
                ),  # BOOT_CFG[0]: DEFAULT_ISP = 1(USB); SECURE_BOOT_EN=1(enabled)
            ],
        )

    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, hour=0, tzinfo=timezone.utc),
    )

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

    # create boot section 0
    boot_section = BootSectionV2(
        0,
        CmdFill(address=0x10C000, pattern=int("063040C0", 16)),
        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))
Beispiel #16
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_regis(
        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, 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)

    # create boot section 0
    boot_section = BootSectionV2(
        0,
        CmdFill(address=0x10C000, pattern=int("063040C0", 16)),
        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))
Beispiel #17
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_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)
Beispiel #18
0
def test_load_cmd_invalid_parse():
    cmd = CmdNop()
    data = cmd.export()
    with pytest.raises(SPSDKError, match="Incorrect header tag"):
        CmdLoad.parse(data)
Beispiel #19
0
def test_nop_cmd_invalid_parse():
    cmd = CmdLoad(address=100, data=b"\x00" * 100)
    data = cmd.export()
    with pytest.raises(SPSDKError, match="Incorrect header tag"):
        CmdNop.parse(data)