Skip to content

Commit

Permalink
Fix build with "fips-link-precompiled" feature
Browse files Browse the repository at this point in the history
When the "fips-link-precompiled" feature is used, the build script for
boringSSL (`boring-sys/build.sh`) adds a precompiled `bcm.o` module
provided by the user. The module is renamed to `bcm-fips.o` and inserted
into `libcrypto.a` just before the `bcm.o` built by the script. The
intent is to "shadow" the module so that, for any symbols that are
provided by both, the linker picks the implementations provided by
`bcm-fips.o`. At the same time, any sybmols in `bcm.o` that are not in
`bcm-fips.o` can be used.

This configuration requires special flags in order to tell the linker
how to resolve duplicate symbols (RUSTFLAGS="-Clink-args=-Wl,-zmuldefs"
is sufficient). However even with these flags thare are certain symbols
that don't resolve. In particular `bcm-fips.o` expects `bcm.o` to
provide `RAND_need_entropy`.

Rather than attempt to cobble together a working version of this
"shadow" build of `libcrypto.a`, we modify the build script so that it
"replaces" `bcm.o` with the precompiled module provided by the user.
Based on internal conversations, this appears to be sufficient for every
use case for these bindings. If the shadow build is required, then the
user will need to provide their own version of `libcrypto.a` (This is
not supported as of this commit.)

One more change is required in order to build with
"fips-link-precompiled". Building fails because the FFI exports a
different API than the bindings expects. To fix this, it is sufficient
to change the features so that "fips-link-precompiled" does not imply
"fips".
  • Loading branch information
cjpatton committed Aug 11, 2023
1 parent a6e35a4 commit 26acb64
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 36 deletions.
8 changes: 5 additions & 3 deletions boring-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ features = ["rpk", "pq-experimental"]
rustdoc-args = ["--cfg", "docsrs"]

[features]
# Use a FIPS-validated version of boringssl.
# Use a FIPS-validated version of boringSSL in `deps/boringssl-fips`.
fips = []

# Link with precompiled FIPS-validated `bcm.o` module.
fips-link-precompiled = ["fips"]
# Use `deps/boringssl`, but replace the `bcm.o` module with a version provided
# by the user. This allows the `bcm.o` module from the FIPS-validated build of
# `libcrypto.a` to be used with a more recent version of boringSSL.
fips-link-precompiled = []

# Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250)
rpk = []
Expand Down
51 changes: 28 additions & 23 deletions boring-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,41 +538,46 @@ fn build_boring_from_sources() -> String {
}

fn link_in_precompiled_bcm_o(bssl_dir: &str) {
println!("cargo:warning=linking in precompiled `bcm.o` module");
const BCM_O_NAME: &str = "bcm.c.o";
println!("cargo:warning=linking in precompiled {BCM_O_NAME}` module");

let bcm_o_src_path = env::var("BORING_SSL_PRECOMPILED_BCM_O")
let precompiled_bcm_o_src_path = env::var("BORING_SSL_PRECOMPILED_BCM_O")
.expect("`fips-link-precompiled` requires `BORING_SSL_PRECOMPILED_BCM_O` env variable to be specified");

let libcrypto_path = PathBuf::from(bssl_dir)
.join("build/crypto/libcrypto.a")
.join("build/libcrypto.a")
.canonicalize()
.unwrap()
.display()
.to_string();

let bcm_o_dst_path = PathBuf::from(bssl_dir).join("build/bcm-fips.o");

fs::copy(bcm_o_src_path, &bcm_o_dst_path).unwrap();

// check that fips module is named as expected
let out = run_command(Command::new("ar").args(["t", &libcrypto_path, "bcm.o"])).unwrap();

assert_eq!(
String::from_utf8(out.stdout).unwrap().trim(),
"bcm.o",
"failed to verify FIPS module name"
);
let precompiled_bcm_o_dst_path = PathBuf::from(bssl_dir).join(&format!("build/{BCM_O_NAME}"));

fs::copy(precompiled_bcm_o_src_path, &precompiled_bcm_o_dst_path).unwrap();

// Check that the `bcm.o` module in `libcrypto.a` has the name we expect it to have.
let out = run_command(Command::new("ar").args(["t", &libcrypto_path, BCM_O_NAME])).unwrap();
if String::from_utf8(out.stdout).unwrap().trim() != BCM_O_NAME {
let mut objects = Vec::new();
let out = String::from_utf8(
run_command(Command::new("ar").args(["t", &libcrypto_path]))
.unwrap()
.stdout,
)
.unwrap();
for object in out.split('\n') {
objects.push(object);
}
panic!("{BCM_O_NAME} not found: {objects:?}");
}

// insert fips bcm.o before bcm.o into libcrypto.a,
// so for all duplicate symbols the older fips bcm.o is used
// (this causes the need for extra linker flags to deal with duplicate symbols)
// (as long as the newer module does not define new symbols, one may also remove it,
// but once there are new symbols it would cause missing symbols at linking stage)
// Modify `libcrypto.a` by replacing the `bcm.o` module with the precompiled module provided by
// the user.
run_command(Command::new("ar").args([
"rb",
"bcm.o",
"br",
BCM_O_NAME,
&libcrypto_path,
bcm_o_dst_path.display().to_string().as_str(),
precompiled_bcm_o_dst_path.display().to_string().as_str(),
]))
.unwrap();
}
Expand Down
8 changes: 5 additions & 3 deletions boring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ features = ["rpk", "pq-experimental"]
rustdoc-args = ["--cfg", "docsrs"]

[features]
# Use a FIPS-validated version of boringssl.
# Use a FIPS-validated version of boringSSL in `deps/boringssl-fips`.
fips = ["boring-sys/fips"]

# Link with precompiled FIPS-validated `bcm.o` module.
fips-link-precompiled = ["fips", "boring-sys/fips-link-precompiled"]
# Use `deps/boringssl`, but replace the `bcm.o` module with a version provided
# by the user. This allows the `bcm.o` module from the FIPS-validated build of
# `libcrypto.a` to be used with a more recent version of boringSSL.
fips-link-precompiled = ["boring-sys/fips-link-precompiled"]

# Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250)
rpk = ["boring-sys/rpk"]
Expand Down
8 changes: 5 additions & 3 deletions hyper-boring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ default = ["runtime"]

runtime = ["hyper/runtime"]

# Use a FIPS-validated version of boringssl.
# Use a FIPS-validated version of boringSSL in `deps/boringssl-fips`.
fips = ["tokio-boring/fips"]

# Link with precompiled FIPS-validated `bcm.o` module.
fips-link-precompiled = ["fips", "tokio-boring/fips-link-precompiled"]
# Use `deps/boringssl`, but replace the `bcm.o` module with a version provided
# by the user. This allows the `bcm.o` module from the FIPS-validated build of
# `libcrypto.a` to be used with a more recent version of boringSSL.
fips-link-precompiled = ["tokio-boring/fips-link-precompiled"]

# Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250)
rpk = ["tokio-boring/rpk"]
Expand Down
10 changes: 6 additions & 4 deletions tokio-boring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ features = ["rpk", "pq-experimental"]
rustdoc-args = ["--cfg", "docsrs"]

[features]
# Use a FIPS-validated version of boringssl.
fips = ["boring/fips", "boring-sys/fips"]
# Use a FIPS-validated version of boringSSL in `deps/boringssl-fips`.
fips = ["boring/fips"]

# Link with precompiled FIPS-validated `bcm.o` module.
fips-link-precompiled = ["fips", "boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"]
# Use `deps/boringssl`, but replace the `bcm.o` module with a version provided
# by the user. This allows the `bcm.o` module from the FIPS-validated build of
# `libcrypto.a` to be used with a more recent version of boringSSL.
fips-link-precompiled = ["boring/fips-link-precompiled"]

# Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250)
rpk = ["boring/rpk"]
Expand Down

0 comments on commit 26acb64

Please sign in to comment.