blob: 98f6f2476bd6dde6fef9a006623b1bdd8915a6e9 [file]
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0
_SEL_DEVICE_ID = 1
_SEL_MANUF_STATE_CREATOR = (1 << 8)
_SEL_MANUF_STATE_OWNER = (1 << 9)
_SEL_LIFE_CYCLE_STATE = (1 << 10)
DEFAULT_USAGE_CONSTRAINTS = 0xa5a5a5a5
_HEX_MAP = "0123456789abcdef"
def hex_digits(v, width = 32):
"""Convert an int into a hex string without 0x prefix"""
if v >= (1 << width):
fail("Int {} too large to convert to string of width {}".format(v, width))
hex_digits = [_HEX_MAP[(v >> i) & 0xf] for i in range(0, width, 4)]
return "".join(reversed(hex_digits))
def hex(v, width = 32):
"""Convert an int into a hex string with 0x prefix"""
return "0x{}".format(hex_digits(v, width = width))
def _manifest_impl(ctx):
mf = {}
mf_version = {}
# All the easy parameters are simple assignments
if ctx.attr.signature:
mf["signature"] = ctx.attr.signature
if ctx.attr.modulus:
mf["modulus"] = ctx.attr.modulus
if ctx.attr.identifier:
mf["identifier"] = ctx.attr.identifier
if ctx.attr.length:
mf["length"] = ctx.attr.length
if ctx.attr.version_major:
mf["version_major"] = ctx.attr.version_major
if ctx.attr.version_minor:
mf["version_minor"] = ctx.attr.version_minor
if ctx.attr.security_version:
mf["security_version"] = ctx.attr.security_version
if ctx.attr.timestamp:
mf["timestamp"] = ctx.attr.timestamp
if ctx.attr.max_key_version:
mf["max_key_version"] = ctx.attr.max_key_version
if ctx.attr.code_start:
mf["code_start"] = ctx.attr.code_start
if ctx.attr.code_end:
mf["code_end"] = ctx.attr.code_end
if ctx.attr.entry_point:
mf["entry_point"] = ctx.attr.entry_point
if ctx.attr.manifest_version_major:
mf_version["major"] = ctx.attr.manifest_version_major
if ctx.attr.manifest_version_minor:
mf_version["minor"] = ctx.attr.manifest_version_minor
if mf_version:
mf["manifest_version"] = mf_version
if ctx.attr.address_translation:
mf["address_translation"] = ctx.attr.address_translation
if ctx.attr.manifest_base_address:
mf["manifest_base_address"] = ctx.attr.manifest_base_address
if ctx.attr.binding_value:
if len(ctx.attr.binding_value) != 8:
fail("The binding_value must be exactly 8 words.")
mf["binding_value"] = [v for v in ctx.attr.binding_value]
uc = {}
selector_bits = 0
device_id = list(ctx.attr.device_id)
if len(device_id) > 8:
fail("The device_id must be 8 words or fewer.")
if len(device_id) < 8:
device_id.extend([hex(DEFAULT_USAGE_CONSTRAINTS)] * (8 - len(device_id)))
for i, d in enumerate(device_id):
if d != hex(DEFAULT_USAGE_CONSTRAINTS):
selector_bits |= _SEL_DEVICE_ID << i
device_id[i] = d
uc["device_id"] = device_id
if ctx.attr.manuf_state_creator:
uc["manuf_state_creator"] = ctx.attr.manuf_state_creator
selector_bits |= _SEL_MANUF_STATE_CREATOR
else:
uc["manuf_state_creator"] = hex(DEFAULT_USAGE_CONSTRAINTS)
if ctx.attr.manuf_state_owner:
uc["manuf_state_owner"] = ctx.attr.manuf_state_owner
selector_bits |= _SEL_MANUF_STATE_OWNER
else:
uc["manuf_state_owner"] = hex(DEFAULT_USAGE_CONSTRAINTS)
if ctx.attr.life_cycle_state:
uc["life_cycle_state"] = ctx.attr.life_cycle_state
selector_bits |= _SEL_LIFE_CYCLE_STATE
else:
uc["life_cycle_state"] = hex(DEFAULT_USAGE_CONSTRAINTS)
if ctx.attr.selector_bits:
if int(ctx.attr.selector_bits, base = 16) != selector_bits and ctx.attr.selector_mismatch_is_failure:
fail("User provided selector_bits ({}) don't match computed selector_bits ({})".format(ctx.attr.selector_bits, selector_bits))
uc["selector_bits"] = ctx.attr.selector_bits
else:
uc["selector_bits"] = selector_bits
mf["usage_constraints"] = uc
extensions = [e or None for e in ctx.attr.extensions] if ctx.attr.extensions else [
"spx_key",
"spx_signature",
"secver_write",
"isfb",
"isfb_erase",
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
]
manifest_dependent_files = []
if ctx.file.owner_transfer_block:
manifest_dependent_files.append(ctx.file.owner_transfer_block)
if ctx.file.owner_transfer_detached_signature:
manifest_dependent_files.append(ctx.file.owner_transfer_detached_signature)
if "owner_transfer_blob" not in extensions:
if None not in extensions:
fail("No free slot in extensions table for owner_transfer_blob.")
extensions[extensions.index(None)] = "owner_transfer_blob"
mf["extensions"] = extensions
mf["extension_params"] = []
if ctx.file.owner_transfer_block:
params = {
"owner_block": ctx.file.owner_transfer_block.path,
}
if ctx.file.owner_transfer_detached_signature:
params["detached_signature"] = ctx.file.owner_transfer_detached_signature.path
mf["extension_params"].append({
"owner_transfer_blob": params,
})
if ctx.attr.integrator_specific_firmware_binding:
mf["extension_params"].append(
{
"integrator_specific_firmware_binding": json.decode(ctx.attr.integrator_specific_firmware_binding),
},
)
secver_write = ctx.attr.secver_write
if secver_write == "none":
pass
elif secver_write in ("false", "true"):
mf["extension_params"].append(
{
"secver_write": {
"secver_write": json.decode(secver_write),
},
},
)
else:
fail("Unknown value for secver_write:", secver_write)
if ctx.attr.isfb_erase_allowed_policy:
mf["extension_params"].append(
{
"isfb_erase_policy": json.decode(ctx.attr.isfb_erase_allowed_policy),
},
)
file = ctx.actions.declare_file("{}.json".format(ctx.attr.name))
ctx.actions.write(file, json.encode_indent(mf))
return [
DefaultInfo(
files = depset([file]),
data_runfiles = ctx.runfiles(files = [file] + manifest_dependent_files),
),
]
_manifest = rule(
implementation = _manifest_impl,
attrs = {
"address_translation": attr.string(doc = "Whether this image uses address translation as a 0x-prefixed hex-encoded string"),
"binding_value": attr.string_list(doc = "Binding value used by key manager to derive secrets as a 0x-prefixed hex-encoded string"),
"code_end": attr.string(doc = "End offset of the executable region in the image as a 0x-prefixed hex-encoded string"),
"code_start": attr.string(doc = "Start offset of the executable region in the image as a 0x-prefixed hex-encoded string"),
"device_id": attr.string_list(doc = "Usage constraint device ID as a 0x-prefixed hex-encoded string"),
"entry_point": attr.string(doc = "Offset of the first instruction in the image as a 0x-prefixed hex-encoded string"),
"extensions": attr.string_list(doc = "Names of the manifest extensions as an array of strings"),
"identifier": attr.string(doc = "Manifest identifier as a 0x-prefixed hex-encoded string"),
"integrator_specific_firmware_binding": attr.string(doc = "Create an Integrator Specific Firmware Block (ISFB) JSON object"),
"isfb_erase_allowed_policy": attr.string(doc = "Create an ISFB Erase Allowed Policy JSON object"),
"length": attr.string(doc = "Length of this image as a 0x-prefixed hex-encoded string"),
"life_cycle_state": attr.string(doc = "Usage constraint for life cycle status as a 0x-prefixed hex-encoded string"),
"manifest_base_address": attr.string(doc = "Manifest base address as a 0x-prefixed hex-encoded string"),
"manifest_version_major": attr.string(doc = "Manifest major version as a 0x-prefixed hex-encoded string"),
"manifest_version_minor": attr.string(doc = "Manifest minor version as a 0x-prefixed hex-encoded string"),
"manuf_state_creator": attr.string(doc = "Usage constraint for silicon creator manufacturing status as a 0x-prefixed hex-encoded string"),
"manuf_state_owner": attr.string(doc = "Usage constraint for silicon owner manufacturing status as a 0x-prefixed hex-encoded string"),
"max_key_version": attr.string(doc = "Maximum allowed version for keys generated at the next boot stage as a 0x-prefixed hex-encoded string"),
"modulus": attr.string(doc = "Signing key modulus as a 0x-prefixed hex-encoded string"),
"owner_transfer_block": attr.label(allow_single_file = True, doc = "The owner block file to include for transfer"),
"owner_transfer_detached_signature": attr.label(allow_single_file = True, doc = "The detached signature of the owner block"),
"security_version": attr.string(doc = "Security version for anti-rollback protection as a 0x-prefixed hex-encoded string"),
"secver_write": attr.string(default = "none", values = ["none", "false", "true"], doc = "Add the secver_write extension with the specified value"),
"selector_bits": attr.string(doc = "Usage constraint selector bits as a 0x-prefixed hex-encoded string"),
"selector_mismatch_is_failure": attr.bool(default = True, doc = "A mismatch in computed selector bits is a failure"),
"signature": attr.string(doc = "Image signature as a 0x-prefixed hex-encoded string"),
"timestamp": attr.string(doc = "Unix timestamp of the image as a 0x-prefixed hex-encoded string"),
"version_major": attr.string(doc = "Image major version as a 0x-prefixed hex-encoded string"),
"version_minor": attr.string(doc = "Image minor version as a 0x-prefixed hex-encoded string"),
},
)
def manifest(name, **kwargs):
_manifest(
name = name,
**kwargs
)
return name