Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RPK and PQ crypto features #126

Merged
merged 4 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,20 @@ jobs:
run: ln -s clang clang++-12
- run: cargo test --features fips
name: Run tests

test-features:
name: Test features
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Install Rust (rustup)
run: rustup update stable --no-self-update && rustup default stable
shell: bash
- run: cargo test --features rpk
name: Run `rpk` tests
- run: cargo test --features pq-experimental
name: Run `pq-experimental` tests
- run: cargo test --features pq-experimental,rpk
name: Run `pq-experimental,rpk` tests
30 changes: 30 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,33 @@ members = [
"tokio-boring",
"hyper-boring"
]
resolver = "2"

[workspace.package]
version = "3.0.0"
repository = "https://github.com/cloudflare/boring"
edition = "2021"

[workspace.dependencies]
boring-sys = { version = "3.0", path = "./boring-sys" }
boring = { version = "3.0", path = "./boring" }
tokio-boring = { version = "3.0", path = "./tokio-boring" }

bindgen = { version = "0.65.1", default-features = false, features = ["runtime"] }
cmake = "0.1"
fslock = "0.2"
bitflags = "1.0"
foreign-types = "0.5"
lazy_static = "1"
libc = "0.2"
hex = "0.4"
rusty-hook = "^0.11"
futures = "0.3"
tokio = { version = "1", features = ["full"] }
anyhow = "1"
antidote = "1.0.0"
http = "0.2"
hyper = { version = "0.14", default-features = false, features = ["full"] }
linked_hash_set = "0.1"
once_cell = "1.0"
tower-layer = "0.3"
33 changes: 5 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,11 @@
BoringSSL bindings for the Rust programming language and TLS adapters for [tokio](https://github.com/tokio-rs/tokio)
and [hyper](https://github.com/hyperium/hyper) built on top of it.

[Documentation](https://docs.rs/boring).

## Release Support

By default, the crate statically links with the latest BoringSSL master branch.

## Support for pre-built binaries

While this crate can build BoringSSL on its own, you may want to provide pre-built binaries instead.
To do so, specify the environment variable `BORING_BSSL_PATH` with the path to the binaries.

You can also provide specific headers by setting `BORING_BSSL_INCLUDE_PATH`.

_Notes_: The crate will look for headers in the `$BORING_BSSL_INCLUDE_PATH/openssl/` folder, make sure to place your headers there.

_Warning_: When providing a different version of BoringSSL make sure to use a compatible one, the crate relies on the presence of certain functions.

## Building with a FIPS-validated module

Only BoringCrypto module version 853ca1ea1168dff08011e5d42d94609cc0ca2e27, as certified with
[FIPS 140-2 certificate 4407](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4407)
is supported by this crate. Support is enabled by this crate's `fips` feature.

`boring-sys` comes with a test that FIPS is enabled/disabled depending on the feature flag. You can run it as follows:

```bash
$ cargo test --features fips fips::is_enabled
```
## Documentation
- Boring API: <https://docs.rs/boring>
- tokio TLS adapters: <https://docs.rs/tokio-boring>
- hyper HTTPS connector: <https://docs.rs/hyper-boring>
- FFI bindings: <https://docs.rs/boring-sys>

## Contribution

Expand Down
27 changes: 21 additions & 6 deletions boring-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[package]
name = "boring-sys"
version = "2.1.0"
version = { workspace = true }
authors = ["Alex Crichton <[email protected]>",
"Steven Fackler <[email protected]>",
"Ivan Nikulin <[email protected]>"]
license = "MIT"
description = "FFI bindings to BoringSSL"
repository = "https://github.com/cloudflare/boring"
repository = { workspace = true }
documentation = "https://docs.rs/boring-sys"
links = "boringssl"
readme = "README.md"
categories = ["cryptography", "external-ffi-bindings"]
edition = "2018"
edition = { workspace = true }
include = [
"/*.md",
"/*.toml",
Expand All @@ -24,12 +24,27 @@ include = [
"/deps/boringssl/LICENSE",
"/build.rs",
"/src",
"/patches",
"/scripts"
]

[build-dependencies]
bindgen = { version = "0.65.1", default-features = false, features = ["runtime"] }
cmake = "0.1"
[package.metadata.docs.rs]
features = ["rpk", "pq-experimental"]
rustdoc-args = ["--cfg", "docsrs"]

[features]
# Use a FIPS-validated version of boringssl.
fips = []

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

# Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/)
pq-experimental = []

[build-dependencies]
bindgen = { workspace = true }
cmake = { workspace = true }
fslock = { workspace = true }


152 changes: 111 additions & 41 deletions boring-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use fslock::LockFile;
use std::env;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;

Expand Down Expand Up @@ -285,7 +289,6 @@ fn get_extra_clang_args_for_bindgen() -> Vec<String> {
#[allow(clippy::single_match)]
match os.as_ref() {
"ios" => {
use std::io::Write;
// When cross-compiling for iOS, tell bindgen to use iOS sysroot,
// and *don't* use system headers of the host macOS.
let sdk = get_ios_sdk_name();
Expand Down Expand Up @@ -325,47 +328,120 @@ fn get_extra_clang_args_for_bindgen() -> Vec<String> {
params
}

fn main() {
use std::env;
fn ensure_patches_applied() -> io::Result<()> {
let mut lock_file = LockFile::open(&PathBuf::from(BORING_SSL_PATH).join(".patch_lock"))?;

println!("cargo:rerun-if-env-changed=BORING_BSSL_PATH");
let bssl_dir = std::env::var("BORING_BSSL_PATH").unwrap_or_else(|_| {
if !Path::new(BORING_SSL_PATH).join("CMakeLists.txt").exists() {
println!("cargo:warning=fetching boringssl git submodule");
// fetch the boringssl submodule
let status = Command::new("git")
.args([
"submodule",
"update",
"--init",
"--recursive",
BORING_SSL_PATH,
])
.status();
if !status.map_or(false, |status| status.success()) {
panic!("failed to fetch submodule - consider running `git submodule update --init --recursive deps/boringssl` yourself");
}
}
lock_file.lock()?;

let mut cfg = get_boringssl_cmake_config();
let boring_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(BORING_SSL_PATH);

if cfg!(feature = "fuzzing") {
cfg.cxxflag("-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE")
.cxxflag("-DBORINGSSL_UNSAFE_FUZZER_MODE");
}
if cfg!(feature = "fips") {
let (clang, clangxx) = verify_fips_clang_version();
cfg.define("CMAKE_C_COMPILER", clang);
cfg.define("CMAKE_CXX_COMPILER", clangxx);
cfg.define("CMAKE_ASM_COMPILER", clang);
cfg.define("FIPS", "1");
let mut cmd = Command::new("git");

cmd.args(["reset", "--hard"]).current_dir(&boring_dir);

run_command(&mut cmd)?;

let mut cmd = Command::new("git");

cmd.args(["clean", "-fdx"]).current_dir(&boring_dir);

run_command(&mut cmd)?;

if cfg!(feature = "pq-experimental") {
println!("cargo:warning=applying experimental post quantum crypto patch to boringssl");
run_apply_patch_script("scripts/apply_pq_patch.sh")?;
}

if cfg!(feature = "rpk") {
println!("cargo:warning=applying RPK patch to boringssl");
run_apply_patch_script("scripts/apply_rpk_patch.sh")?;
}

Ok(())
}

fn run_command(command: &mut Command) -> io::Result<()> {
let exit_status = command.spawn()?.wait()?;

if !exit_status.success() {
let err = match exit_status.code() {
Some(code) => format!("{:?} exited with status: {}", command, code),
None => format!("{:?} was terminated by signal", command),
};

return Err(io::Error::new(io::ErrorKind::Other, err));
}

Ok(())
}

fn run_apply_patch_script(script_path: impl AsRef<Path>) -> io::Result<()> {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let src_path = manifest_dir.join(BORING_SSL_PATH).canonicalize()?;
let cmd_path = manifest_dir.join(script_path).canonicalize()?;

let mut cmd = Command::new(cmd_path);
cmd.current_dir(src_path);
run_command(&mut cmd)?;

Ok(())
}

fn build_boring_from_sources() -> String {
if !Path::new(BORING_SSL_PATH).join("CMakeLists.txt").exists() {
println!("cargo:warning=fetching boringssl git submodule");
// fetch the boringssl submodule
let status = Command::new("git")
.args([
"submodule",
"update",
"--init",
"--recursive",
BORING_SSL_PATH,
])
.status();

if !status.map_or(false, |status| status.success()) {
panic!("failed to fetch submodule - consider running `git submodule update --init --recursive deps/boringssl` yourself");
}
}

cfg.build_target("ssl").build();
cfg.build_target("crypto").build().display().to_string()
});
ensure_patches_applied().unwrap();

let mut cfg = get_boringssl_cmake_config();

if cfg!(feature = "fuzzing") {
cfg.cxxflag("-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE")
.cxxflag("-DBORINGSSL_UNSAFE_FUZZER_MODE");
}
if cfg!(feature = "fips") {
let (clang, clangxx) = verify_fips_clang_version();
cfg.define("CMAKE_C_COMPILER", clang);
cfg.define("CMAKE_CXX_COMPILER", clangxx);
cfg.define("CMAKE_ASM_COMPILER", clang);
cfg.define("FIPS", "1");
}

cfg.build_target("ssl").build();
cfg.build_target("crypto").build().display().to_string()
}

fn main() {
println!("cargo:rerun-if-env-changed=BORING_BSSL_PATH");

#[cfg(all(feature = "fips", feature = "rpk"))]
compile_error!("`fips` and `rpk` features are mutually exclusive");

let bssl_dir = std::env::var("BORING_BSSL_PATH");

if bssl_dir.is_ok() && cfg!(any(feature = "rpk", feature = "pq-experimental")) {
panic!("precompiled BoringSSL was provided, optional patches can't be applied to it");
}

let bssl_dir = bssl_dir.unwrap_or_else(|_| build_boring_from_sources());

let build_path = get_boringssl_platform_output_path();

if cfg!(feature = "fips") {
println!(
"cargo:rustc-link-search=native={}/build/crypto/{}",
Expand All @@ -385,12 +461,6 @@ fn main() {
println!("cargo:rustc-link-lib=static=crypto");
println!("cargo:rustc-link-lib=static=ssl");

// MacOS: Allow cdylib to link with undefined symbols
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
if target_os == "macos" {
println!("cargo:rustc-cdylib-link-arg=-Wl,-undefined,dynamic_lookup");
}

println!("cargo:rerun-if-env-changed=BORING_BSSL_INCLUDE_PATH");
let include_path = std::env::var("BORING_BSSL_INCLUDE_PATH").unwrap_or_else(|_| {
if cfg!(feature = "fips") {
Expand Down
Loading