Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into jnelson/update-upst…
Browse files Browse the repository at this point in the history
…ream-boring-merge

I intentionally retained the following changes:
- FIPS support for non-32-bit non-Windows platforms, see #65
- FIPS support for `X509StoreContextRef::chain`, see #66

Upstream has had roughly the following changes since the last merge:
- FIPS support
- Updated dependencies
- Git submodules are fetched automatically
- Support for pre-built versions of boringssl using `BORING_BSSL_PATH` and `BORING_BSSL_INCLUDE_PATH`
- Support for `HandshakeError::code` and `ClientHello::client_version`
  • Loading branch information
jyn514 committed Feb 1, 2022
2 parents 5931043 + 1507689 commit 7e8b2d8
Show file tree
Hide file tree
Showing 61 changed files with 647 additions and 531 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,18 @@ jobs:
- if: "!startsWith(matrix.os, 'windows')"
run: cargo test
name: Run tests (not Windows)

test-fips:
name: Test FIPS integration
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Install Rust (rustup)
run: rustup update stable --no-self-update && rustup default stable
shell: bash
- name: Install Clang-7
run: sudo apt-get install -y clang-7
- run: cargo test --features fips
name: Run tests
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
ignore = dirty
[submodule "boring-sys/deps/boringssl-fips"]
path = boring-sys/deps/boringssl-fips
url = ssh://[email protected]:7999/sys/boringssl.git
url = ssh://[email protected]:7999/sys/boringssl.git
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Change Log

## [Unreleased]

## [v2.0.0] - 2021-12-16

### Changed

* Updated `foreign-types` from 0.3 to 0.5. This is technically a breaking change if you used `foreign-types` in your own crate, but in practice this shouldn't have a large impact.
* Removed unused `*Ref` structs; these served no purpose and were not useful.
* Removed unused `tempdir` dependency
29 changes: 26 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,39 @@

[![crates.io](https://img.shields.io/crates/v/boring.svg)](https://crates.io/crates/boring)

BoringSSL bindings for the Rust programming language and TLS adapters for [tokio](https://github.com/tokio-rs/tokio)
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

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

### Contribution
## 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 ae223d6138807a13006342edfeef32e813246b39, as
certified with [certificate
3678](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3678)
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
```

## Contribution

Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
Expand Down
17 changes: 17 additions & 0 deletions boring-sys/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Change Log

## [Unreleased]

## [v2.0.0] - 2021-12-16

### Added

* Allow using pre-built binaries of `bssl` using the `BORING_BSSL_PATH` env variable
* Automatically fetch the `boringssl` submodule if it doesn't yet exist

### Changed

* Removed unused `PasswordCallback` type
* Disable unused bindgen dependencies
* Update `bindgen` and `bytes` dependencies
*
11 changes: 6 additions & 5 deletions boring-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "boring-sys"
version = "1.1.1"
version = "2.0.0"
authors = ["Alex Crichton <[email protected]>",
"Steven Fackler <[email protected]>",
"Ivan Nikulin <[email protected]>"]
Expand All @@ -26,10 +26,11 @@ include = [
"/src",
]

[features]
fips = []

[build-dependencies]
bindgen = "0.57"
bindgen = { version = "0.59", default-features = false, features = ["runtime"] }
cmake = "0.1"
libc = "0.2"

[features]
# Use a FIPS-validated version of boringssl.
fips = []
161 changes: 126 additions & 35 deletions boring-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
use std::path::{Path, PathBuf};
use std::process::Command;

// NOTE: this build script is adopted from quiche (https://github.com/cloudflare/quiche)
use std::fs::File;
use std::io;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::Command;

#[cfg(not(feature = "fips"))]
const BORING_SSL_DIR: &str = "deps/boringssl";

#[cfg(feature = "fips")]
const BORING_SSL_DIR: &str = "deps/boringssl-fips";

// Additional parameters for Android build of BoringSSL.
//
Expand Down Expand Up @@ -96,6 +91,11 @@ fn get_boringssl_platform_output_path() -> String {
}
}

#[cfg(feature = "fips")]
const BORING_SSL_PATH: &str = "deps/boringssl-fips";
#[cfg(not(feature = "fips"))]
const BORING_SSL_PATH: &str = "deps/boringssl";

/// Returns a new cmake::Config for building BoringSSL.
///
/// It will add platform-specific parameters if needed.
Expand All @@ -104,7 +104,7 @@ fn get_boringssl_cmake_config() -> cmake::Config {
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let pwd = std::env::current_dir().unwrap();

let mut boringssl_cmake = cmake::Config::new(BORING_SSL_DIR);
let mut boringssl_cmake = cmake::Config::new(BORING_SSL_PATH);

// Add platform-specific parameters.
match os.as_ref() {
Expand All @@ -116,6 +116,7 @@ fn get_boringssl_cmake_config() -> cmake::Config {
};

// We need ANDROID_NDK_HOME to be set properly.
println!("cargo:rerun-if-env-changed=ANDROID_NDK_HOME");
let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
.expect("Please set ANDROID_NDK_HOME for Android build");
let android_ndk_home = std::path::Path::new(&android_ndk_home);
Expand Down Expand Up @@ -171,9 +172,9 @@ fn get_boringssl_cmake_config() -> cmake::Config {
// Configure BoringSSL for building on 32-bit non-windows platforms.
if arch == "x86" && os != "windows" {
let toolchain_file = if cfg!(feature = "fips") {
format!("{}/util/32-bit-toolchain.cmake", BORING_SSL_DIR)
format!("{}/util/32-bit-toolchain.cmake", BORING_SSL_PATH)
} else {
format!("{}/src/util/32-bit-toolchain.cmake", BORING_SSL_DIR)
format!("{}/src/util/32-bit-toolchain.cmake", BORING_SSL_PATH)
};

boringssl_cmake
Expand Down Expand Up @@ -201,13 +202,18 @@ fn run_command(command: &mut Command) -> io::Result<()> {
}

fn boring_ssl_path() -> PathBuf {
std::fs::canonicalize(format!("{}/{}", env!("CARGO_MANIFEST_DIR"), BORING_SSL_DIR)).unwrap()
std::fs::canonicalize(format!(
"{}/{}",
env!("CARGO_MANIFEST_DIR"),
BORING_SSL_PATH
))
.unwrap()
}

fn ensure_rpk_patch_applied() -> io::Result<()> {
use libc::{flock, LOCK_EX, LOCK_NB};

let lock_file = format!("{}/.has_rpk_patch", BORING_SSL_DIR);
let lock_file = format!("{}/.has_rpk_patch", BORING_SSL_PATH);
if std::fs::metadata(&lock_file).is_ok() {
return Ok(());
}
Expand Down Expand Up @@ -236,32 +242,110 @@ fn ensure_rpk_patch_applied() -> io::Result<()> {
Ok(())
}

/// Verify that the toolchains match https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3678.pdf
/// See "Installation Instructions" under section 12.1.
// TODO: maybe this should also verify the Go and Ninja versions? But those haven't been an issue in practice ...
fn verify_fips_clang_version() -> (&'static str, &'static str) {
fn version(tool: &str) -> String {
let output = match Command::new(tool).arg("--version").output() {
Ok(o) => o,
Err(e) => {
eprintln!("warning: missing {}, trying other compilers: {}", tool, e);
// NOTE: hard-codes that the loop below checks the version
return String::new();
}
};
assert!(output.status.success());
let output = std::str::from_utf8(&output.stdout).expect("invalid utf8 output");
output.lines().next().expect("empty output").to_string()
}

const REQUIRED_CLANG_VERSION: &str = "7.0.1";
for (cc, cxx) in [
("clang-7", "clang++-7"),
("clang", "clang++"),
("cc", "c++"),
] {
let cc_version = version(cc);
if cc_version.contains(REQUIRED_CLANG_VERSION) {
assert!(
version(cxx).contains(REQUIRED_CLANG_VERSION),
"mismatched versions of cc and c++"
);
return (cc, cxx);
} else if cc == "cc" {
panic!(
"unsupported clang version \"{}\": FIPS requires clang {}",
cc_version, REQUIRED_CLANG_VERSION
);
} else if !cc_version.is_empty() {
eprintln!(
"warning: FIPS requires clang version {}, skipping incompatible version \"{}\"",
REQUIRED_CLANG_VERSION, cc_version
);
}
}
unreachable!()
}

fn main() -> io::Result<()> {
use std::env;

if !cfg!(feature = "fips") {
ensure_rpk_patch_applied()?;
}

let mut cfg = get_boringssl_cmake_config();
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");
}
}

if cfg!(feature = "fuzzing") {
cfg.cxxflag("-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE")
.cxxflag("-DBORINGSSL_UNSAFE_FUZZER_MODE");
}
let mut cfg = get_boringssl_cmake_config();

if cfg!(feature = "fips") {
cfg.define("FIPS", "1");
}
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("bssl").build().display().to_string()
});

let bssl_dir = cfg.build_target("bssl").build().display().to_string();
let build_path = get_boringssl_platform_output_path();
let build_dir = format!("{}/build/{}", bssl_dir, build_path);
if cfg!(feature = "fips") {
println!("cargo:rustc-link-search=native={}/crypto", build_dir);
println!("cargo:rustc-link-search=native={}/ssl", build_dir);
println!(
"cargo:rustc-link-search=native={}/build/crypto/{}",
bssl_dir, build_path
);
println!(
"cargo:rustc-link-search=native={}/build/ssl/{}",
bssl_dir, build_path
);
} else {
println!("cargo:rustc-link-search=native={}", build_dir);
println!(
"cargo:rustc-link-search=native={}/build/{}",
bssl_dir, build_path
);
}

println!("cargo:rustc-link-lib=static=crypto");
Expand All @@ -272,11 +356,14 @@ fn main() -> io::Result<()> {
println!("cargo:rustc-cdylib-link-arg=-Wl,-undefined,dynamic_lookup");
}

let include_path = if cfg!(feature = "fips") {
PathBuf::from(format!("{}/include", BORING_SSL_DIR))
} else {
PathBuf::from(format!("{}/src/include", BORING_SSL_DIR))
};
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") {
format!("{}/include", BORING_SSL_PATH)
} else {
format!("{}/src/include", BORING_SSL_PATH)
}
});

let mut builder = bindgen::Builder::default()
.derive_copy(true)
Expand All @@ -291,7 +378,7 @@ fn main() -> io::Result<()> {
.layout_tests(true)
.prepend_enum_name(true)
.rustfmt_bindings(true)
.clang_args(&["-I", include_path.to_str().unwrap()]);
.clang_args(&["-I", &include_path]);

let headers = [
"aes.h",
Expand Down Expand Up @@ -325,11 +412,15 @@ fn main() -> io::Result<()> {
#[cfg(not(feature = "fips"))]
"trust_token.h",
"x509v3.h",
#[cfg(feature = "fips")]
"x509.h",
];
for header in &headers {
builder = builder.header(include_path.join("openssl").join(header).to_str().unwrap());
builder = builder.header(
Path::new(&include_path)
.join("openssl")
.join(header)
.to_str()
.unwrap(),
);
}

let bindings = builder.generate().expect("Unable to generate bindings");
Expand Down
Loading

0 comments on commit 7e8b2d8

Please sign in to comment.