Skip to content

Commit ca1f605

Browse files
committed
[crypto] binary blob: add compilation rule
Add a custom compilation rule in bazel that compiles crypto into a binary blob and include this blob into libotcrypto. This library can then be used for an application and allows to perform a self-integrity check on the binary blob. Try it out via ./bazelisk build //sw/device/lib/crypto:cryptolib --config=fips_all Also added two rules to get the elf or dis of the cryptolib in this mode. With thanks to Elieva Pignat <elievap@google.com> Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent f9da08f commit ca1f605

File tree

3 files changed

+330
-3
lines changed

3 files changed

+330
-3
lines changed

rules/opentitan/cc.bzl

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,227 @@ def _build_binary(ctx, exec_env, name, deps, kind):
237237
)
238238
return provides, signed
239239

240+
def _opentitan_binary_blob(ctx):
241+
"""
242+
Create a library containing the library as a binary blob and a parser to
243+
this binary blob. The following steps are done to create the final library:
244+
- Generate jump table and its parser from public header files and a linker
245+
script for the creation of the binary blob
246+
- Compile the jump table with the library and create an executable
247+
from it using the linker script
248+
- Extract the binary from the executable (the last bytes can contain the hash
249+
- Compute the hash of the binary file and replace its last bytes by the hash
250+
- Create a c file that contain the binary blob as an array
251+
- Compile the parser and the binary blob array
252+
- Create the library
253+
"""
254+
255+
# Name for the files generated by this rule
256+
name_jump_table_c = ctx.attr.name + "_jump_table.c"
257+
name_jump_table_h = ctx.attr.name + "_jump_table.h"
258+
name_lib_parser = ctx.attr.name + "_lib_parser.c"
259+
name_linker_script = ctx.attr.name + "_linker_script.ld"
260+
name_elf = ctx.attr.name + ".elf"
261+
name_bin = ctx.attr.name + ".bin"
262+
name_sha = ctx.attr.name + ".sha384"
263+
name_bin_sha = ctx.attr.name + "_sha384.bin"
264+
name_blob = ctx.attr.name + "_blob.c"
265+
name_library = ctx.attr.name + ".a"
266+
267+
deps_blob = ctx.attr.deps_blob
268+
deps_lib = ctx.attr.deps
269+
270+
cc_toolchain = find_cc_toolchain(ctx)
271+
272+
# Declare output files generated by generate_jump_table.py.
273+
linker_script = ctx.actions.declare_file(name_linker_script)
274+
jump_table_c = ctx.actions.declare_file(name_jump_table_c)
275+
jump_table_h = ctx.actions.declare_file(name_jump_table_h)
276+
lib_parser_c = ctx.actions.declare_file(name_lib_parser)
277+
278+
# Prepare the arguments for generate_jump_table.py
279+
extra_args = []
280+
if ctx.attr.pic:
281+
extra_args.append("--pic")
282+
283+
if len(ctx.files.config) == 1:
284+
extra_args.append("--config={}".format(ctx.files.config[0].path))
285+
286+
header = ctx.attr.header
287+
header_list = [h for head in ctx.attr.header for h in head.files.to_list()]
288+
address = ctx.var.get("ADDRESS", "0")
289+
290+
# Generate jump table and parser files from public headers
291+
ctx.actions.run(
292+
outputs = [linker_script, jump_table_c, jump_table_h, lib_parser_c],
293+
inputs = header_list + [ctx.files.config[0]],
294+
arguments = [
295+
"--binary_blob",
296+
"--address={}".format(address),
297+
"--out-dir={}".format(jump_table_c.dirname),
298+
"--prefix={}".format(ctx.attr.name),
299+
] + extra_args + [h.path for h in header_list],
300+
executable = ctx.executable._generate_jump_table,
301+
)
302+
303+
features = cc_common.configure_features(
304+
ctx = ctx,
305+
cc_toolchain = cc_toolchain,
306+
requested_features = ctx.features,
307+
unsupported_features = ctx.disabled_features,
308+
)
309+
310+
compilation_contexts = [
311+
dep_blob[CcInfo].compilation_context
312+
for dep_blob in deps_blob
313+
]
314+
315+
# Compile the jump table and include it to libotcrypto library
316+
hdrs = [jump_table_h]
317+
srcs = [jump_table_c]
318+
cctx, cout = cc_common.compile(
319+
name = ctx.attr.name,
320+
actions = ctx.actions,
321+
feature_configuration = features,
322+
cc_toolchain = cc_toolchain,
323+
compilation_contexts = compilation_contexts,
324+
srcs = srcs,
325+
private_hdrs = hdrs,
326+
user_compile_flags = ["-ffreestanding"] + _expand(ctx, "copts", ctx.attr.copts),
327+
defines = _expand(ctx, "defines", ctx.attr.defines),
328+
local_defines = _expand(ctx, "local_defines", ctx.attr.local_defines),
329+
quote_includes = _expand(ctx, "includes", ctx.attr.includes),
330+
)
331+
332+
linking_contexts = [
333+
dep_blob[CcInfo].linking_context
334+
for dep_blob in deps_blob
335+
]
336+
337+
# Add the linker script to the linking_contexts
338+
linking_input = cc_common.create_linker_input(owner = ctx.label, additional_inputs = depset([linker_script]))
339+
linking_contexts.append(cc_common.create_linking_context(linker_inputs = depset([linking_input])))
340+
extra_linkopts = (ctx.attr.linkopts or [])
341+
342+
linkopts = [
343+
"-static",
344+
"-nostdlib",
345+
"-nostartfiles",
346+
"-Wl,-T{}".format(linker_script.path),
347+
] + _expand(ctx, "linkopts", extra_linkopts)
348+
349+
# Create an executable from the libotcrypto by using the linker script
350+
elf_file = ctx.actions.declare_file(name_elf)
351+
linking_outputs = cc_common.link(
352+
name = name_elf,
353+
actions = ctx.actions,
354+
output_type = "executable",
355+
feature_configuration = features,
356+
cc_toolchain = cc_toolchain,
357+
compilation_outputs = cout,
358+
linking_contexts = linking_contexts,
359+
user_link_flags = linkopts,
360+
)
361+
362+
# Create a disassembly file from the elf file
363+
dis_file = obj_disassemble(
364+
ctx,
365+
name = ctx.attr.name,
366+
src = linking_outputs.executable,
367+
)
368+
369+
# Extract the binary from the elf file
370+
binary_file = ctx.actions.declare_file(name_bin)
371+
ctx.actions.run(
372+
outputs = [binary_file],
373+
inputs = [elf_file],
374+
executable = ctx.executable._riscv32_objcopy,
375+
arguments = ["-O", "binary", elf_file.path, binary_file.path],
376+
use_default_shell_env = True,
377+
)
378+
379+
# Compute the hash of the binary file
380+
hash_file = ctx.actions.declare_file(name_sha)
381+
ctx.actions.run_shell(
382+
inputs = [binary_file],
383+
outputs = [hash_file],
384+
# Remove the last 48 bytes (the hash table) before computing the hash
385+
command = "head -c -48 {} | sha384sum | awk '{{print $1}}' | xxd -r -p > {}".format(binary_file.path, hash_file.path),
386+
)
387+
388+
# Compute the hash of the binary file
389+
binary_hash_file = ctx.actions.declare_file(name_bin_sha)
390+
ctx.actions.run_shell(
391+
inputs = [binary_file, hash_file],
392+
outputs = [binary_hash_file],
393+
# Replace the last 48 bytes by the hash
394+
command = "head -c -48 {} > {} && cat {} >> {}".format(binary_file.path, binary_hash_file.path, hash_file.path, binary_hash_file.path),
395+
)
396+
397+
# Generate a C file that contain an array (blob) of the binary file content
398+
blob_file = ctx.actions.declare_file(name_blob)
399+
ctx.actions.run_shell(
400+
inputs = [binary_hash_file],
401+
outputs = [blob_file],
402+
command = "xxd -i -n blob {} | sed 's/unsigned char/const unsigned char __attribute__((section (\".text.blob\"), aligned(4)))/' > {}"
403+
.format(binary_hash_file.path, blob_file.path),
404+
)
405+
406+
# Creation of the library that contains the binary blob and lib_parser.c
407+
# to be able to parse it
408+
srcs_lib = [blob_file, lib_parser_c]
409+
hdrs_lib = ctx.files.hdrs + [jump_table_h] + header_list
410+
compilation_contexts = [
411+
dep_lib[CcInfo].compilation_context
412+
for dep_lib in deps_lib
413+
]
414+
415+
(ctx_object, objects) = cc_common.compile(
416+
name = ctx.attr.name,
417+
actions = ctx.actions,
418+
feature_configuration = features,
419+
cc_toolchain = cc_toolchain,
420+
compilation_contexts = compilation_contexts,
421+
srcs = srcs_lib,
422+
private_hdrs = hdrs_lib,
423+
user_compile_flags = _expand(ctx, "copts", ctx.attr.copts),
424+
defines = _expand(ctx, "defines", ctx.attr.defines),
425+
local_defines = _expand(ctx, "local_defines", ctx.attr.local_defines),
426+
quote_includes = _expand(ctx, "includes", ctx.attr.includes),
427+
)
428+
429+
# Create a library from it
430+
object_files = objects.objects
431+
library_file = ctx.actions.declare_file(name_library)
432+
ctx.actions.run(
433+
inputs = object_files,
434+
outputs = [library_file],
435+
executable = ctx.executable._riscv32_ar,
436+
arguments = ["rcs", library_file.path] + [obj.path for obj in object_files],
437+
)
438+
439+
return [
440+
DefaultInfo(files = depset([library_file, dis_file, elf_file])),
441+
OutputGroupInfo(
442+
elf_file = depset([linking_outputs.executable]),
443+
dis_file = depset([dis_file]),
444+
),
445+
CcInfo(
446+
# The context allows consumers to link against this library
447+
linking_context = cc_common.create_linking_context(
448+
linker_inputs = depset([cc_common.create_linker_input(
449+
owner = ctx.label,
450+
libraries = depset([cc_common.create_library_to_link(
451+
actions = ctx.actions,
452+
feature_configuration = features,
453+
cc_toolchain = cc_toolchain,
454+
static_library = library_file,
455+
)]),
456+
)]),
457+
),
458+
),
459+
]
460+
240461
def _opentitan_binary(ctx):
241462
providers = []
242463
default_info = []
@@ -361,6 +582,53 @@ common_binary_attrs = {
361582
),
362583
}
363584

585+
opentitan_binary_blob = rv_rule(
586+
implementation = _opentitan_binary_blob,
587+
attrs = dict(common_binary_attrs.items() + {
588+
"hdrs": attr.label_list(
589+
allow_files = True,
590+
doc = "The list of header file requires for the creation of the library.",
591+
),
592+
"header": attr.label_list(
593+
allow_files = True,
594+
doc = "Public header files to generate jump_table and parser.",
595+
),
596+
"config": attr.label(
597+
default = None,
598+
allow_files = True,
599+
doc = "File containing the functions to be included into the blob",
600+
),
601+
"deps_blob": attr.label_list(
602+
providers = [CcInfo],
603+
doc = "The list of other libraries to be for the creation of the binary blob.",
604+
),
605+
"pic": attr.bool(
606+
default = False,
607+
doc = "Indicate if the code is position independent ",
608+
),
609+
"_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
610+
"_riscv32_objcopy": attr.label(
611+
default = Label("@lowrisc_rv32imcb_toolchain//:bin/riscv32-unknown-elf-objcopy"),
612+
allow_single_file = True,
613+
executable = True,
614+
cfg = "exec",
615+
),
616+
"_riscv32_ar": attr.label(
617+
default = Label("@lowrisc_rv32imcb_toolchain//:bin/riscv32-unknown-elf-ar"),
618+
allow_single_file = True,
619+
executable = True,
620+
cfg = "exec",
621+
),
622+
"_generate_jump_table": attr.label(
623+
default = "//util:generate_jump_table",
624+
executable = True,
625+
cfg = "exec",
626+
),
627+
}.items()),
628+
fragments = ["cpp"],
629+
toolchains = ["@rules_cc//cc:toolchain_type"],
630+
)
631+
364632
opentitan_binary = rv_rule(
365633
implementation = _opentitan_binary,
366634
attrs = dict(common_binary_attrs.items() + {

rules/opentitan/defs.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ load(
1313
load(
1414
"@lowrisc_opentitan//rules/opentitan:cc.bzl",
1515
_opentitan_binary = "opentitan_binary",
16+
_opentitan_binary_blob = "opentitan_binary_blob",
1617
_opentitan_test = "opentitan_test",
1718
)
1819
load(
@@ -76,6 +77,7 @@ OPENTITAN_PLATFORM = _OPENTITAN_PLATFORM
7677
opentitan_transition = _opentitan_transition
7778

7879
opentitan_binary = _opentitan_binary
80+
opentitan_binary_blob = _opentitan_binary_blob
7981
fpga_cw305 = _fpga_cw305
8082
fpga_cw310 = _fpga_cw310
8183
fpga_cw340 = _fpga_cw340

sw/device/lib/crypto/BUILD

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
package(default_visibility = ["//visibility:public"])
66

7-
load("//rules/opentitan:defs.bzl", "OPENTITAN_CPU")
7+
load("//rules/opentitan:defs.bzl", "OPENTITAN_CPU", "opentitan_binary_blob")
88
load("//rules/opentitan:static_library.bzl", "ot_static_library")
99
load("@rules_pkg//pkg:mappings.bzl", "pkg_files")
1010
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
11+
load("//rules:linker.bzl", "ld_library")
1112

1213
cc_library(
1314
name = "otcrypto_api",
@@ -45,13 +46,59 @@ cc_library(
4546
],
4647
)
4748

49+
opentitan_binary_blob(
50+
name = "otcrypto_binary_blob_api",
51+
config = select({
52+
"//rules/configs:fips_all": "//rules/configs:fips_all.txt",
53+
"//conditions:default": None,
54+
}),
55+
deps_blob = [
56+
":otcrypto_api",
57+
"//sw/device/lib/crypto/include:crypto_hdrs",
58+
"//sw/device/lib/base:memory",
59+
"//sw/device/lib/runtime:log",
60+
],
61+
# Public headers so generate_jump_table.py can parse them
62+
header = [
63+
"//sw/device/lib/crypto/include:aes.h",
64+
"//sw/device/lib/crypto/include:aes_gcm.h",
65+
"//sw/device/lib/crypto/include:drbg.h",
66+
"//sw/device/lib/crypto/include:ecc_curve25519.h",
67+
"//sw/device/lib/crypto/include:ecc_p256.h",
68+
"//sw/device/lib/crypto/include:ecc_p384.h",
69+
"//sw/device/lib/crypto/include:hkdf.h",
70+
"//sw/device/lib/crypto/include:hmac.h",
71+
"//sw/device/lib/crypto/include:kdf_ctr.h",
72+
"//sw/device/lib/crypto/include:key_transport.h",
73+
"//sw/device/lib/crypto/include:kmac.h",
74+
"//sw/device/lib/crypto/include:kmac_kdf.h",
75+
"//sw/device/lib/crypto/include:otcrypto.h",
76+
"//sw/device/lib/crypto/include:rsa.h",
77+
"//sw/device/lib/crypto/include:security_config.h",
78+
"//sw/device/lib/crypto/include:sha2.h",
79+
"//sw/device/lib/crypto/include:sha3.h",
80+
"//sw/device/lib/crypto/include:x25519.h",
81+
],
82+
linkopts = select({
83+
"//rules/configs:pic": ["-mno-relax"],
84+
"//conditions:default": [],
85+
}),
86+
pic = select({
87+
"//rules/configs:pic": True,
88+
"//conditions:default": False,
89+
}),
90+
deps = [
91+
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
92+
"//sw/device/lib/crypto/include:crypto_hdrs",
93+
],
94+
)
95+
4896
# Top-level cryptolib target.
4997
ot_static_library(
5098
name = "otcrypto",
5199
deps = select({
52100
"//rules/configs:type_static": [":otcrypto_api"],
53-
# Only static type is supported for the moment
54-
#"//rules/configs:type_binary_blob": [":otcrypto_binary_blob_api"],
101+
"//rules/configs:type_binary_blob": [":otcrypto_binary_blob_api"],
55102
#"//rules/configs:type_relocatable": [":otcrypto_relocatable_api",],
56103
"//conditions:default": [],
57104
}),
@@ -105,3 +152,13 @@ pkg_tar(
105152
],
106153
extension = "tar.xz",
107154
)
155+
156+
filegroup(
157+
name = "otcrypto_binary_blob_elf",
158+
srcs = [":otcrypto_binary_blob_api"],
159+
)
160+
161+
filegroup(
162+
name = "otcrypto_binary_blob_dis",
163+
srcs = [":otcrypto_binary_blob_api"],
164+
)

0 commit comments

Comments
 (0)