From bf8a7f6af576e8b322760362cd8c02d1c5fefcb8 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Tue, 2 Jan 2024 15:53:23 -0700 Subject: [PATCH 01/22] Add dependency-review CI action --- .github/workflows/dependency-review.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/dependency-review.yaml diff --git a/.github/workflows/dependency-review.yaml b/.github/workflows/dependency-review.yaml new file mode 100644 index 00000000..9ea1ba16 --- /dev/null +++ b/.github/workflows/dependency-review.yaml @@ -0,0 +1,12 @@ +name: Dependency Review + +on: + pull_request: + merge_group: + +jobs: + dependency-review: + uses: gravitational/shared-workflows/.github/workflows/dependency-review.yaml@main + permissions: + contents: read + pull-requests: write From 2ed46c1bb0cda27bd4aa26b0d42fc6d84caa82a7 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 18 Dec 2023 12:42:11 +0100 Subject: [PATCH 02/22] Introduce X509CheckFlags::UNDERSCORE_WILDCARDS --- .github/workflows/ci.yml | 8 + boring-sys/Cargo.toml | 7 +- boring-sys/build.rs | 743 ++++++++++++++++++ boring-sys/build/config.rs | 8 +- boring-sys/build/main.rs | 5 + boring-sys/patches/underscore-wildcards.patch | 61 ++ boring/Cargo.toml | 7 +- boring/src/ssl/test/mod.rs | 73 +- boring/src/x509/verify.rs | 2 + boring/test/cert-wildcard.pem | 20 + 10 files changed, 929 insertions(+), 5 deletions(-) create mode 100644 boring-sys/build.rs create mode 100644 boring-sys/patches/underscore-wildcards.patch create mode 100644 boring/test/cert-wildcard.pem diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98ab144f..e64a5c1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -340,7 +340,15 @@ jobs: name: Run `rpk` tests - run: cargo test --features pq-experimental name: Run `pq-experimental` tests + - run: cargo test --features underscore-wildcards + name: Run `underscore-wildcards` tests - run: cargo test --features pq-experimental,rpk name: Run `pq-experimental,rpk` tests - run: cargo test --features kx-safe-default,pq-experimental name: Run `kx-safe-default` tests + - run: cargo test --features pq-experimental,underscore-wildcards + name: Run `pq-experimental,underscore-wildcards` tests + - run: cargo test --features rpk,underscore-wildcards + name: Run `rpk,underscore-wildcards` tests + - run: cargo test --features pq-experimental,rpk,underscore-wildcards + name: Run `pq-experimental,rpk,underscore-wildcards` tests diff --git a/boring-sys/Cargo.toml b/boring-sys/Cargo.toml index b6257348..c1471f20 100644 --- a/boring-sys/Cargo.toml +++ b/boring-sys/Cargo.toml @@ -51,7 +51,7 @@ include = [ ] [package.metadata.docs.rs] -features = ["rpk", "pq-experimental"] +features = ["rpk", "pq-experimental", "underscore-wildcards"] rustdoc-args = ["--cfg", "docsrs"] [features] @@ -71,6 +71,11 @@ rpk = [] # can be provided by setting `BORING_BSSL{,_FIPS}_SOURCE_PATH`. pq-experimental = [] +# Applies a patch (`patches/underscore-wildcards.patch`) to enable +# `ffi::X509_CHECK_FLAG_UNDERSCORE_WILDCARDS`. Same caveats as +# those for `pq-experimental` feature apply. +underscore-wildcards = [] + [build-dependencies] bindgen = { workspace = true } cmake = { workspace = true } diff --git a/boring-sys/build.rs b/boring-sys/build.rs new file mode 100644 index 00000000..e71886d5 --- /dev/null +++ b/boring-sys/build.rs @@ -0,0 +1,743 @@ +use fslock::LockFile; +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; +use std::sync::Once; + +// NOTE: this build script is adopted from quiche (https://github.com/cloudflare/quiche) + +// Additional parameters for Android build of BoringSSL. +// +// Android NDK < 18 with GCC. +const CMAKE_PARAMS_ANDROID_NDK_OLD_GCC: &[(&str, &[(&str, &str)])] = &[ + ( + "aarch64", + &[("ANDROID_TOOLCHAIN_NAME", "aarch64-linux-android-4.9")], + ), + ( + "arm", + &[("ANDROID_TOOLCHAIN_NAME", "arm-linux-androideabi-4.9")], + ), + ( + "x86", + &[("ANDROID_TOOLCHAIN_NAME", "x86-linux-android-4.9")], + ), + ( + "x86_64", + &[("ANDROID_TOOLCHAIN_NAME", "x86_64-linux-android-4.9")], + ), +]; + +// Android NDK >= 19. +const CMAKE_PARAMS_ANDROID_NDK: &[(&str, &[(&str, &str)])] = &[ + ("aarch64", &[("ANDROID_ABI", "arm64-v8a")]), + ("arm", &[("ANDROID_ABI", "armeabi-v7a")]), + ("x86", &[("ANDROID_ABI", "x86")]), + ("x86_64", &[("ANDROID_ABI", "x86_64")]), +]; + +fn cmake_params_android() -> &'static [(&'static str, &'static str)] { + let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let cmake_params_android = if cfg!(feature = "ndk-old-gcc") { + CMAKE_PARAMS_ANDROID_NDK_OLD_GCC + } else { + CMAKE_PARAMS_ANDROID_NDK + }; + for (android_arch, params) in cmake_params_android { + if *android_arch == arch { + return params; + } + } + &[] +} + +const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[ + // iOS + ( + "aarch64-apple-ios", + &[ + ("CMAKE_OSX_ARCHITECTURES", "arm64"), + ("CMAKE_OSX_SYSROOT", "iphoneos"), + ], + ), + ( + "aarch64-apple-ios-sim", + &[ + ("CMAKE_OSX_ARCHITECTURES", "arm64"), + ("CMAKE_OSX_SYSROOT", "iphonesimulator"), + ], + ), + ( + "x86_64-apple-ios", + &[ + ("CMAKE_OSX_ARCHITECTURES", "x86_64"), + ("CMAKE_OSX_SYSROOT", "iphonesimulator"), + ], + ), + // macOS + ( + "aarch64-apple-darwin", + &[ + ("CMAKE_OSX_ARCHITECTURES", "arm64"), + ("CMAKE_OSX_SYSROOT", "macosx"), + ], + ), + ( + "x86_64-apple-darwin", + &[ + ("CMAKE_OSX_ARCHITECTURES", "x86_64"), + ("CMAKE_OSX_SYSROOT", "macosx"), + ], + ), +]; + +fn cmake_params_apple() -> &'static [(&'static str, &'static str)] { + let target = env::var("TARGET").unwrap(); + for (next_target, params) in CMAKE_PARAMS_APPLE { + if *next_target == target { + return params; + } + } + &[] +} + +fn get_apple_sdk_name() -> &'static str { + for (name, value) in cmake_params_apple() { + if *name == "CMAKE_OSX_SYSROOT" { + return value; + } + } + let target = env::var("TARGET").unwrap(); + panic!("cannot find SDK for {} in CMAKE_PARAMS_APPLE", target); +} + +/// Returns an absolute path to the BoringSSL source. +fn get_boringssl_source_path() -> String { + #[cfg(feature = "fips")] + const SUBMODULE_DIR: &str = "boringssl-fips"; + #[cfg(not(feature = "fips"))] + const SUBMODULE_DIR: &str = "boringssl"; + + static COPY_SOURCES: Once = Once::new(); + + if let Ok(src_path) = env::var("BORING_BSSL_SOURCE_PATH") { + return src_path; + } + + let out_dir = env::var("OUT_DIR").unwrap(); + let src_path = Path::new(&out_dir).join(SUBMODULE_DIR); + + COPY_SOURCES.call_once(|| { + let submodule_path = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("deps") + .join(SUBMODULE_DIR); + + if !submodule_path.join("CMakeLists.txt").exists() { + println!("cargo:warning=fetching boringssl git submodule"); + + run_command(Command::new("git").args([ + "submodule", + "update", + "--init", + "--recursive", + &submodule_path.display().to_string(), + ])) + .unwrap(); + } + + let _ = fs::remove_dir_all(&src_path); + fs_extra::dir::copy(submodule_path, &out_dir, &Default::default()).unwrap(); + + // NOTE: .git can be both file and dir, depening on whether it was copied from a submodule + // or created by the patches code. + let src_git_path = src_path.join(".git"); + let _ = fs::remove_file(&src_git_path); + let _ = fs::remove_dir_all(&src_git_path); + }); + + src_path.display().to_string() +} + +/// Returns the platform-specific output path for lib. +/// +/// MSVC generator on Windows place static libs in a target sub-folder, +/// so adjust library location based on platform and build target. +/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18 +fn get_boringssl_platform_output_path() -> String { + if cfg!(target_env = "msvc") { + // Code under this branch should match the logic in cmake-rs + let debug_env_var = env::var("DEBUG").expect("DEBUG variable not defined in env"); + + let deb_info = match &debug_env_var[..] { + "false" => false, + "true" => true, + unknown => panic!("Unknown DEBUG={} env var.", unknown), + }; + + let opt_env_var = env::var("OPT_LEVEL").expect("OPT_LEVEL variable not defined in env"); + + let subdir = match &opt_env_var[..] { + "0" => "Debug", + "1" | "2" | "3" => { + if deb_info { + "RelWithDebInfo" + } else { + "Release" + } + } + "s" | "z" => "MinSizeRel", + unknown => panic!("Unknown OPT_LEVEL={} env var.", unknown), + }; + + subdir.to_string() + } else { + "".to_string() + } +} + +/// Returns a new cmake::Config for building BoringSSL. +/// +/// It will add platform-specific parameters if needed. +fn get_boringssl_cmake_config() -> cmake::Config { + let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let host = env::var("HOST").unwrap(); + let target = env::var("TARGET").unwrap(); + let pwd = std::env::current_dir().unwrap(); + let src_path = get_boringssl_source_path(); + + let mut boringssl_cmake = cmake::Config::new(&src_path); + if host != target { + // Add platform-specific parameters for cross-compilation. + match os.as_ref() { + "android" => { + // We need ANDROID_NDK_HOME to be set properly. + println!("cargo:rerun-if-env-changed=ANDROID_NDK_HOME"); + let android_ndk_home = 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); + for (name, value) in cmake_params_android() { + eprintln!("android arch={} add {}={}", arch, name, value); + boringssl_cmake.define(name, value); + } + let toolchain_file = android_ndk_home.join("build/cmake/android.toolchain.cmake"); + let toolchain_file = toolchain_file.to_str().unwrap(); + eprintln!("android toolchain={}", toolchain_file); + boringssl_cmake.define("CMAKE_TOOLCHAIN_FILE", toolchain_file); + + // 21 is the minimum level tested. You can give higher value. + boringssl_cmake.define("ANDROID_NATIVE_API_LEVEL", "21"); + boringssl_cmake.define("ANDROID_STL", "c++_shared"); + } + + "macos" => { + for (name, value) in cmake_params_apple() { + eprintln!("macos arch={} add {}={}", arch, name, value); + boringssl_cmake.define(name, value); + } + } + + "ios" => { + for (name, value) in cmake_params_apple() { + eprintln!("ios arch={} add {}={}", arch, name, value); + boringssl_cmake.define(name, value); + } + + // Bitcode is always on. + let bitcode_cflag = "-fembed-bitcode"; + + // Hack for Xcode 10.1. + let target_cflag = if arch == "x86_64" { + "-target x86_64-apple-ios-simulator" + } else { + "" + }; + + let cflag = format!("{} {}", bitcode_cflag, target_cflag); + boringssl_cmake.define("CMAKE_ASM_FLAGS", &cflag); + boringssl_cmake.cflag(&cflag); + } + + "windows" => { + if host.contains("windows") { + // BoringSSL's CMakeLists.txt isn't set up for cross-compiling using Visual Studio. + // Disable assembly support so that it at least builds. + boringssl_cmake.define("OPENSSL_NO_ASM", "YES"); + } + } + + "linux" => match arch.as_str() { + "x86" => { + boringssl_cmake.define( + "CMAKE_TOOLCHAIN_FILE", + pwd.join(&src_path) + .join("src/util/32-bit-toolchain.cmake") + .as_os_str(), + ); + } + "aarch64" => { + boringssl_cmake.define( + "CMAKE_TOOLCHAIN_FILE", + pwd.join("cmake/aarch64-linux.cmake").as_os_str(), + ); + } + "arm" => { + boringssl_cmake.define( + "CMAKE_TOOLCHAIN_FILE", + pwd.join("cmake/armv7-linux.cmake").as_os_str(), + ); + } + _ => { + eprintln!( + "warning: no toolchain file configured by boring-sys for {}", + target + ); + } + }, + + _ => {} + } + } + + boringssl_cmake +} + +/// 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(); + } + }; + if !output.status.success() { + return String::new(); + } + 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 = "12.0.0"; + for (cc, cxx) in [ + ("clang-12", "clang++-12"), + ("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 pick_best_android_ndk_toolchain(toolchains_dir: &Path) -> std::io::Result { + let toolchains = std::fs::read_dir(toolchains_dir)?.collect::, _>>()?; + // First look for one of the toolchains that Google has documented. + // https://developer.android.com/ndk/guides/other_build_systems + for known_toolchain in ["linux-x86_64", "darwin-x86_64", "windows-x86_64"] { + if let Some(toolchain) = toolchains + .iter() + .find(|entry| entry.file_name() == known_toolchain) + { + return Ok(toolchain.file_name()); + } + } + // Then fall back to any subdirectory, in case Google has added support for a new host. + // (Maybe there's a linux-aarch64 toolchain now.) + if let Some(toolchain) = toolchains + .into_iter() + .find(|entry| entry.file_type().map(|ty| ty.is_dir()).unwrap_or(false)) + { + return Ok(toolchain.file_name()); + } + // Finally give up. + Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + "no subdirectories at given path", + )) +} + +fn get_extra_clang_args_for_bindgen() -> Vec { + let os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + + let mut params = Vec::new(); + + // Add platform-specific parameters. + #[allow(clippy::single_match)] + match os.as_ref() { + "ios" | "macos" => { + // When cross-compiling for Apple targets, tell bindgen to use SDK sysroot, + // and *don't* use system headers of the host macOS. + let sdk = get_apple_sdk_name(); + let output = std::process::Command::new("xcrun") + .args(["--show-sdk-path", "--sdk", sdk]) + .output() + .unwrap(); + if !output.status.success() { + if let Some(exit_code) = output.status.code() { + eprintln!("xcrun failed: exit code {}", exit_code); + } else { + eprintln!("xcrun failed: killed"); + } + std::io::stderr().write_all(&output.stderr).unwrap(); + // Uh... let's try anyway, I guess? + return params; + } + let mut sysroot = String::from_utf8(output.stdout).unwrap(); + // There is typically a newline at the end which confuses clang. + sysroot.truncate(sysroot.trim_end().len()); + params.push("-isysroot".to_string()); + params.push(sysroot); + } + "android" => { + let android_ndk_home = env::var("ANDROID_NDK_HOME") + .expect("Please set ANDROID_NDK_HOME for Android build"); + let mut android_sysroot = std::path::PathBuf::from(android_ndk_home); + android_sysroot.extend(["toolchains", "llvm", "prebuilt"]); + let toolchain = match pick_best_android_ndk_toolchain(&android_sysroot) { + Ok(toolchain) => toolchain, + Err(e) => { + eprintln!( + "warning: failed to find prebuilt Android NDK toolchain for bindgen: {}", + e + ); + // Uh... let's try anyway, I guess? + return params; + } + }; + android_sysroot.push(toolchain); + android_sysroot.push("sysroot"); + params.push("--sysroot".to_string()); + // If ANDROID_NDK_HOME weren't a valid UTF-8 string, + // we'd already know from env::var. + params.push(android_sysroot.into_os_string().into_string().unwrap()); + } + _ => {} + } + + params +} + +fn ensure_patches_applied() -> io::Result<()> { + let out_dir = env::var("OUT_DIR").unwrap(); + let mut lock_file = LockFile::open(&PathBuf::from(&out_dir).join(".patch_lock"))?; + let src_path = get_boringssl_source_path(); + let has_git = Path::new(&src_path).join(".git").exists(); + + lock_file.lock()?; + + // NOTE: init git in the copied files, so we can apply patches + if !has_git { + run_command(Command::new("git").args(["init"]).current_dir(&src_path))?; + } + + if cfg!(feature = "pq-experimental") { + println!("cargo:warning=applying experimental post quantum crypto patch to boringssl"); + apply_patch("boring-pq.patch")?; + } + + if cfg!(feature = "rpk") { + println!("cargo:warning=applying RPK patch to boringssl"); + apply_patch("rpk.patch")?; + } + + Ok(()) +} + +fn apply_patch(patch_name: &str) -> io::Result<()> { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let src_path = get_boringssl_source_path(); + let cmd_path = manifest_dir + .join("patches") + .join(patch_name) + .canonicalize()?; + + run_command( + Command::new("git") + .args([ + "apply", + "-v", + "--whitespace=fix", + &cmd_path.display().to_string(), + ]) + .current_dir(src_path), + )?; + + Ok(()) +} + +fn run_command(command: &mut Command) -> io::Result { + let out = command.output()?; + + println!("{}", std::str::from_utf8(&out.stdout).unwrap()); + eprintln!("{}", std::str::from_utf8(&out.stderr).unwrap()); + + if !out.status.success() { + let err = match out.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(out) +} + +fn build_boring_from_sources() -> String { + if cfg!(feature = "no-patches") { + println!( + "cargo:warning=skipping git patches application, provided\ + native BoringSSL is expected to have the patches included" + ); + } else { + 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"); + } + + if cfg!(feature = "fips-link-precompiled") { + cfg.define("FIPS", "1"); + } + + cfg.build_target("ssl").build(); + cfg.build_target("crypto").build().display().to_string() +} + +fn link_in_precompiled_bcm_o(bssl_dir: &str) { + println!("cargo:warning=linking in precompiled `bcm.o` module"); + + let 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") + .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" + ); + + // 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) + run_command(Command::new("ar").args([ + "rb", + "bcm.o", + &libcrypto_path, + bcm_o_dst_path.display().to_string().as_str(), + ])) + .unwrap(); +} + +fn check_feature_compatibility() { + #[cfg(all(feature = "fips", feature = "rpk"))] + compile_error!("`fips` and `rpk` features are mutually exclusive"); + + let no_patches_enabled = cfg!(feature = "no-patches"); + let is_external_native_lib_source = + env::var("BORING_BSSL_PATH").is_err() && env::var("BORING_BSSL_SOURCE_PATH").is_err(); + + if no_patches_enabled && is_external_native_lib_source { + panic!( + "`no-patches` feature is supposed to be used with `BORING_BSSL_PATH`\ + or `BORING_BSSL_SOURCE_PATH` env variables" + ) + } + + let features_with_patches_enabled = cfg!(any(feature = "rpk", feature = "pq-experimental")); + let patches_required = features_with_patches_enabled && !no_patches_enabled; + let build_from_sources_required = cfg!(feature = "fips-link-precompiled") || patches_required; + let is_precompiled_native_lib = env::var("BORING_BSSL_PATH").is_ok(); + + if is_precompiled_native_lib && build_from_sources_required { + panic!("precompiled BoringSSL was provided, so FIPS configuration or optional patches can't be applied"); + } +} + +fn main() { + println!("cargo:rerun-if-env-changed=BORING_BSSL_PATH"); + println!("cargo:rerun-if-env-changed=BORING_BSSL_INCLUDE_PATH"); + println!("cargo:rerun-if-env-changed=BORING_BSSL_SOURCE_PATH"); + println!("cargo:rerun-if-env-changed=BORING_SSL_PRECOMPILED_BCM_O"); + println!("cargo:rerun-if-env-changed=BORINGSSL_BUILD_DIR"); + + check_feature_compatibility(); + + let bssl_dir = env::var("BORING_BSSL_PATH").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/{}", + bssl_dir, build_path + ); + println!( + "cargo:rustc-link-search=native={}/build/ssl/{}", + bssl_dir, build_path + ); + println!( + "cargo:rustc-link-search=native={}/lib/{}", + bssl_dir, build_path + ); + } else { + println!( + "cargo:rustc-link-search=native={}/build/{}", + bssl_dir, build_path + ); + } + + if cfg!(feature = "fips-link-precompiled") { + link_in_precompiled_bcm_o(&bssl_dir); + } + + println!("cargo:rustc-link-lib=static=crypto"); + println!("cargo:rustc-link-lib=static=ssl"); + + let include_path = env::var("BORING_BSSL_INCLUDE_PATH").unwrap_or_else(|_| { + if let Ok(bssl_path) = env::var("BORING_BSSL_PATH") { + return format!("{}/include", bssl_path); + } + + let src_path = get_boringssl_source_path(); + + if Path::new(&src_path).join("include").exists() { + format!("{}/include", &src_path) + } else { + format!("{}/src/include", &src_path) + } + }); + + let mut builder = bindgen::Builder::default() + .derive_copy(true) + .derive_debug(true) + .derive_default(true) + .derive_eq(true) + .default_enum_style(bindgen::EnumVariation::NewType { + is_bitfield: false, + is_global: false, + }) + .default_macro_constant_type(bindgen::MacroTypeVariation::Signed) + .generate_comments(true) + .fit_macro_constants(false) + .size_t_is_usize(true) + .layout_tests(true) + .prepend_enum_name(true) + .clang_args(get_extra_clang_args_for_bindgen()) + .clang_args(&["-I", &include_path]); + + let target = env::var("TARGET").unwrap(); + match target.as_ref() { + // bindgen produces alignment tests that cause undefined behavior [1] + // when applied to explicitly unaligned types like OSUnalignedU64. + // + // There is no way to disable these tests for only some types + // and it's not nice to suppress warnings for the entire crate, + // so let's disable all alignment tests and hope for the best. + // + // [1]: https://github.com/rust-lang/rust-bindgen/issues/1651 + "aarch64-apple-ios" | "aarch64-apple-ios-sim" => { + builder = builder.layout_tests(false); + } + _ => {} + } + + let headers = [ + "aes.h", + "asn1_mac.h", + "asn1t.h", + "blake2.h", + "blowfish.h", + "cast.h", + "chacha.h", + "cmac.h", + "cpu.h", + "curve25519.h", + "des.h", + "dtls1.h", + "hkdf.h", + "hmac.h", + "hrss.h", + "md4.h", + "md5.h", + "obj_mac.h", + "objects.h", + "opensslv.h", + "ossl_typ.h", + "pkcs12.h", + "poly1305.h", + "rand.h", + "rc4.h", + "ripemd.h", + "siphash.h", + "srtp.h", + "trust_token.h", + "x509v3.h", + ]; + for header in &headers { + builder = builder.header( + Path::new(&include_path) + .join("openssl") + .join(header) + .to_str() + .unwrap(), + ); + } + + let bindings = builder.generate().expect("Unable to generate bindings"); + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index 79d119fc..d05396ae 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -18,6 +18,7 @@ pub(crate) struct Features { pub(crate) fips_link_precompiled: bool, pub(crate) pq_experimental: bool, pub(crate) rpk: bool, + pub(crate) underscore_wildcards: bool, } pub(crate) struct Env { @@ -82,7 +83,10 @@ impl Config { ); } - let features_with_patches_enabled = self.features.rpk || self.features.pq_experimental; + let features_with_patches_enabled = self.features.rpk + || self.features.pq_experimental + || self.features.underscore_wildcards; + let patches_required = features_with_patches_enabled && !self.env.assume_patched; let build_from_sources_required = self.features.fips_link_precompiled || patches_required; @@ -98,12 +102,14 @@ impl Features { let fips_link_precompiled = env::var_os("CARGO_FEATURE_FIPS_LINK_PRECOMPILED").is_some(); let pq_experimental = env::var_os("CARGO_FEATURE_PQ_EXPERIMENTAL").is_some(); let rpk = env::var_os("CARGO_FEATURE_RPK").is_some(); + let underscore_wildcards = env::var_os("CARGO_FEATURE_UNDERSCORE_WILDCARDS").is_some(); Self { fips, fips_link_precompiled, pq_experimental, rpk, + underscore_wildcards, } } } diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index b2ed72f6..68f24c35 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -491,6 +491,11 @@ fn ensure_patches_applied(config: &Config) -> io::Result<()> { apply_patch(config, "rpk.patch")?; } + if config.features.underscore_wildcards { + println!("cargo:warning=applying underscore wildcards patch to boringssl"); + apply_patch(config, "underscore-wildcards.patch")?; + } + Ok(()) } diff --git a/boring-sys/patches/underscore-wildcards.patch b/boring-sys/patches/underscore-wildcards.patch new file mode 100644 index 00000000..f281b3a1 --- /dev/null +++ b/boring-sys/patches/underscore-wildcards.patch @@ -0,0 +1,61 @@ +https://github.com/google/boringssl/compare/master...cloudflare:boringssl:underscore-wildcards + +--- a/src/crypto/x509v3/v3_utl.c ++++ b/src/crypto/x509v3/v3_utl.c +@@ -790,7 +790,9 @@ static int wildcard_match(const unsigned char *prefix, size_t prefix_len, + // Check that the part matched by the wildcard contains only + // permitted characters and only matches a single label. + for (p = wildcard_start; p != wildcard_end; ++p) { +- if (!OPENSSL_isalnum(*p) && *p != '-') { ++ if (!OPENSSL_isalnum(*p) && *p != '-' && ++ !(*p == '_' && ++ (flags & X509_CHECK_FLAG_UNDERSCORE_WILDCARDS))) { + return 0; + } + } +--- a/src/crypto/x509/x509_test.cc ++++ b/src/crypto/x509/x509_test.cc +@@ -4500,6 +4500,31 @@ TEST(X509Test, Names) { + /*invalid_emails=*/{}, + /*flags=*/0, + }, ++ ++ // Underscores in DNS names are forbidden by default. ++ { ++ /*cert_subject=*/{}, ++ /*cert_dns_names=*/{"*.example.com"}, ++ /*cert_emails=*/{}, ++ /*valid_dns_names=*/{}, ++ /*invalid_dns_names=*/{"not_allowed.example.com"}, ++ /*valid_emails=*/{}, ++ /*invalid_emails=*/{}, ++ /*flags=*/0, ++ }, ++ ++ // Underscores in DNS names can be allowed with the right flag. ++ { ++ /*cert_subject=*/{}, ++ /*cert_dns_names=*/{"*.example.com"}, ++ /*cert_emails=*/{}, ++ /*valid_dns_names=*/{"now_allowed.example.com"}, ++ /*invalid_dns_names=*/{}, ++ /*valid_emails=*/{}, ++ /*invalid_emails=*/{}, ++ /*flags=*/X509_CHECK_FLAG_UNDERSCORE_WILDCARDS, ++ }, ++ + }; + + size_t i = 0; +--- a/src/include/openssl/x509c3.h ++++ b/src/include/openssl/x509v3.h +@@ -4497,6 +4497,8 @@ OPENSSL_EXPORT int X509_PURPOSE_get_id(const X509_PURPOSE *); + #define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0 + // Skip the subject common name fallback if subjectAltNames is missing. + #define X509_CHECK_FLAG_NEVER_CHECK_SUBJECT 0x20 ++// Allow underscores in DNS wildcard matches. ++#define X509_CHECK_FLAG_UNDERSCORE_WILDCARDS 0x40 + + OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername); +-- diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 64564907..0a576ab4 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -12,7 +12,7 @@ categories = ["cryptography", "api-bindings"] edition = { workspace = true } [package.metadata.docs.rs] -features = ["rpk", "pq-experimental"] +features = ["rpk", "pq-experimental", "underscore-wildcards"] rustdoc-args = ["--cfg", "docsrs"] [features] @@ -38,6 +38,11 @@ rpk = ["boring-sys/rpk"] # `BORING_BSSL{,_FIPS}_SOURCE_PATH` and `BORING_BSSL{,_FIPS}_ASSUME_PATCHED`. pq-experimental = ["boring-sys/pq-experimental"] +# Applies a patch to enable +# `ffi::X509_CHECK_FLAG_UNDERSCORE_WILDCARDS`. Same caveats as +# those for `pq-experimental` feature apply. +underscore-wildcards = ["boring-sys/underscore-wildcards"] + # Controlling key exchange preferences at compile time # Choose key exchange preferences at compile time. This prevents the user from diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 29b85ac3..90f203e4 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -503,12 +503,81 @@ fn verify_valid_hostname() { client.ctx().set_verify(SslVerifyMode::PEER); + let mut client = client.build().builder(); + + client.ssl().param_mut().set_host("foobar.com").unwrap(); + client.connect(); +} + +#[test] +fn verify_valid_hostname_with_wildcard() { + let mut server = Server::builder(); + + server + .ctx() + .set_certificate_chain_file("test/cert-wildcard.pem") + .unwrap(); + + let server = server.build(); + let mut client = server.client_with_root_ca(); + + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + client.ssl().param_mut().set_host("yes.foobar.com").unwrap(); + client.connect(); +} + +#[test] +fn verify_reject_underscore_hostname_with_wildcard() { + let mut server = Server::builder(); + + server.should_error(); + server + .ctx() + .set_certificate_chain_file("test/cert-wildcard.pem") + .unwrap(); + + let server = server.build(); + let mut client = server.client_with_root_ca(); + + client.ctx().set_verify(SslVerifyMode::PEER); + let mut client = client.build().builder(); client .ssl() .param_mut() - .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); - client.ssl().param_mut().set_host("foobar.com").unwrap(); + .set_host("not_allowed.foobar.com") + .unwrap(); + client.connect_err(); +} + +#[cfg(feature = "underscore-wildcards")] +#[test] +fn verify_allow_underscore_hostname_with_wildcard() { + let mut server = Server::builder(); + + server + .ctx() + .set_certificate_chain_file("test/cert-wildcard.pem") + .unwrap(); + + let server = server.build(); + let mut client = server.client_with_root_ca(); + + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + + client + .ssl() + .param_mut() + .set_hostflags(X509CheckFlags::UNDERSCORE_WILDCARDS); + client + .ssl() + .param_mut() + .set_host("now_allowed.foobar.com") + .unwrap(); client.connect(); } diff --git a/boring/src/x509/verify.rs b/boring/src/x509/verify.rs index 8bc17a58..decc3092 100644 --- a/boring/src/x509/verify.rs +++ b/boring/src/x509/verify.rs @@ -16,6 +16,8 @@ bitflags! { const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS as _; const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS as _; const NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT as _; + #[cfg(feature = "underscore-wildcards")] + const UNDERSCORE_WILDCARDS = ffi::X509_CHECK_FLAG_UNDERSCORE_WILDCARDS as _; #[deprecated(since = "0.10.6", note = "renamed to NO_WILDCARDS")] const FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS as _; diff --git a/boring/test/cert-wildcard.pem b/boring/test/cert-wildcard.pem new file mode 100644 index 00000000..825e411f --- /dev/null +++ b/boring/test/cert-wildcard.pem @@ -0,0 +1,20 @@ +notAfter=Aug 12 11:30:03 2026 GMT +-----BEGIN CERTIFICATE----- +MIIDKDCCAhACFGwwuilXOHjBjQ584FD9drp9Uh/LMA0GCSqGSIb3DQEBCwUAMEUx +CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjMxMjE4MTEzMDAzWhcNMjYwODEyMTEz +MDAzWjBcMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE +BwwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYDVQQDDAwqLmZvb2Jhci5j +b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo9CWMRLMXo1CF/iOR +h9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0kU6o +5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNSwiHA +1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAMjmal +oZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iTHk7F +14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCtOzbo +Kgs1AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHG83qKMl5bPoL2s7TaJZ909NaQO +4C69ueXlD4HJEFe7L9mkeQoDaF7RwWSBwN2RZT5hzQhghRotqLA06XwKbQHji/R7 +sYYVUHunobFUHsr51tFN1BIDoAWJa0N2rm/OxbcK471eWNKjMiS2vvvPdaMxxHAx +IsjAJBJec4IxNIUNNKqCS/xNYcdiyrmmU3oFWGqb0As/eDOBw0Amd0aayasFJrRV +3KZI5OcFg/J3XvdaxMJD+RPyUysKRXg6K8jzYc/PB8LhWVXpLxjEzeO2IHCaZprh +dUTP8+Ob+ioxujvlslxc4nrrUD5EWwnpEIr7e4af27JHQVaNyHbRw6wI2uk= +-----END CERTIFICATE----- From c8869297d4032d4b833872779d982b7dc0225a73 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 20 Dec 2023 19:41:54 +0100 Subject: [PATCH 03/22] Don't use self-signed certs in hyper-boring tests --- Cargo.toml | 1 + hyper-boring/Cargo.toml | 1 + hyper-boring/src/test.rs | 32 +++++++++++++++------ hyper-boring/test/cert.pem | 36 ++++++++++++------------ hyper-boring/test/key.pem | 52 +++++++++++++++++------------------ hyper-boring/test/root-ca.pem | 21 ++++++++++++++ 6 files changed, 90 insertions(+), 53 deletions(-) create mode 100644 hyper-boring/test/root-ca.pem diff --git a/Cargo.toml b/Cargo.toml index d94deced..f6425f4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,4 +40,5 @@ http = "0.2" hyper = { version = "0.14", default-features = false } linked_hash_set = "0.1" once_cell = "1.0" +tower = "0.4" tower-layer = "0.3" diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index 29c30560..cd9991e6 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -42,4 +42,5 @@ tower-layer = { workspace = true } [dev-dependencies] hyper = { workspace = true, features = [ "full" ] } tokio = { workspace = true, features = [ "full" ] } +tower = { workspace = true, features = ["util"] } futures = { workspace = true } diff --git a/hyper-boring/src/test.rs b/hyper-boring/src/test.rs index 226a0487..e1b30f07 100644 --- a/hyper-boring/src/test.rs +++ b/hyper-boring/src/test.rs @@ -5,6 +5,8 @@ use hyper::client::HttpConnector; use hyper::server::conn::Http; use hyper::{service, Response}; use hyper::{Body, Client}; +use std::convert::Infallible; +use std::iter; use tokio::net::TcpListener; #[tokio::test] @@ -28,7 +30,8 @@ async fn google() { #[tokio::test] async fn localhost() { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let port = listener.local_addr().unwrap().port(); + let addr = listener.local_addr().unwrap(); + let port = addr.port(); let server = async move { let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); @@ -57,10 +60,16 @@ async fn localhost() { }; tokio::spawn(server); - let mut connector = HttpConnector::new(); + let resolver = + tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); + + let mut connector = HttpConnector::new_with_resolver(resolver); + connector.enforce_http(false); + let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - ssl.set_ca_file("test/cert.pem").unwrap(); + + ssl.set_ca_file("test/root-ca.pem").unwrap(); use std::fs::File; use std::io::Write; @@ -75,7 +84,7 @@ async fn localhost() { for _ in 0..3 { let resp = client - .get(format!("https://localhost:{}", port).parse().unwrap()) + .get(format!("https://foobar.com:{}", port).parse().unwrap()) .await .unwrap(); assert!(resp.status().is_success(), "{}", resp.status()); @@ -89,7 +98,8 @@ async fn alpn_h2() { use boring::ssl::{self, AlpnError}; let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let port = listener.local_addr().unwrap().port(); + let addr = listener.local_addr().unwrap(); + let port = addr.port(); let server = async move { let mut acceptor = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap(); @@ -119,17 +129,23 @@ async fn alpn_h2() { }; tokio::spawn(server); - let mut connector = HttpConnector::new(); + let resolver = + tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); + + let mut connector = HttpConnector::new_with_resolver(resolver); + connector.enforce_http(false); + let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - ssl.set_ca_file("test/cert.pem").unwrap(); + + ssl.set_ca_file("test/root-ca.pem").unwrap(); ssl.set_alpn_protos(b"\x02h2\x08http/1.1").unwrap(); let ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); let client = Client::builder().build::<_, Body>(ssl); let resp = client - .get(format!("https://localhost:{}", port).parse().unwrap()) + .get(format!("https://foobar.com:{}", port).parse().unwrap()) .await .unwrap(); assert!(resp.status().is_success(), "{}", resp.status()); diff --git a/hyper-boring/test/cert.pem b/hyper-boring/test/cert.pem index 2d08323d..032fe60e 100644 --- a/hyper-boring/test/cert.pem +++ b/hyper-boring/test/cert.pem @@ -1,21 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDhTCCAm2gAwIBAgIJALClJS+cq+ykMA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNjExMjgwNTU5 -MjNaFw0yNjExMjYwNTU5MjNaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l -LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV -BAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL4k -A0mghV17MPi033tKh1IK4pM6zpzHFrgi2smU97O/kxvSbNnDoZHEdqq3AtRcjELg -HeKTd02jyAHxGoRTAVORIp0p4LCCvlR7EnHH78e3vIq3lkLe5uqyujnx2NJJIrIX -r5Y+Z3QuMUSAix6GreAb19KcTZG82igvh4dOQP/pmlqQsyrPpioLy50O2NuBqU5Q -xyevFRHsWfe3M7ayzJBVwMpDJxg3saOETXgzMzfKtrj2Pw0mfcHQMtsPv7z85ug0 -yyd9iXwwLYx2RqZ6epChsWuY2zj7Zfcis3DzbsrW8/J758KNkjZVWS9aJmDGsT3R -xRlVDnIeow/SWi5qtqECAwEAAaNQME4wHQYDVR0OBBYEFNU1F6I+C06y6rN1yjn0 -i/ARufw1MB8GA1UdIwQYMBaAFNU1F6I+C06y6rN1yjn0i/ARufw1MAwGA1UdEwQF -MAMBAf8wDQYJKoZIhvcNAQELBQADggEBACvFmTY+QSrc9EIAtuGk20L4OHrkOoRv -veMIu3PAGbrzjE0rRC1qeLqkqudlWCk+xE6nNe90tB0qyY8AOgj68K2OplrJIhqt -rxJ/Ohtbepwi53Q5npRoib6f9aL+FuT0hnVtVon2ngWRizSdH/CY7vCWuJjTtlon -3J8TGPA1cnj8FtEEfF3ISd0/XCE2oar875FOscf7S0eLnORbuunCVU/RaNn25h/r -9EhvoaPZ6cSZpt7UliMkSt6b07/A2SwU5C19BS1XoqGH02P9OV0pmuJn7N/fOGer -aVbDiPpb+UAUHFUSyu32iK6T2/6OuJS7MQ1cI2biB2SWgWNBTmhRF1s= +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== -----END CERTIFICATE----- diff --git a/hyper-boring/test/key.pem b/hyper-boring/test/key.pem index 58f1020a..d381795d 100644 --- a/hyper-boring/test/key.pem +++ b/hyper-boring/test/key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+JANJoIVdezD4 -tN97SodSCuKTOs6cxxa4ItrJlPezv5Mb0mzZw6GRxHaqtwLUXIxC4B3ik3dNo8gB -8RqEUwFTkSKdKeCwgr5UexJxx+/Ht7yKt5ZC3ubqsro58djSSSKyF6+WPmd0LjFE -gIsehq3gG9fSnE2RvNooL4eHTkD/6ZpakLMqz6YqC8udDtjbgalOUMcnrxUR7Fn3 -tzO2ssyQVcDKQycYN7GjhE14MzM3yra49j8NJn3B0DLbD7+8/OboNMsnfYl8MC2M -dkamenqQobFrmNs4+2X3IrNw827K1vPye+fCjZI2VVkvWiZgxrE90cUZVQ5yHqMP -0louarahAgMBAAECggEAd08brQCHjs/1O6orLS7n2IgyAhZ9fQzD6ckdJi5Oe8Cz -K1sPqFlEMbZoi9iIcv6bmH8O4ZSM4O/rWaSTcgKvq2M/qASWE8wGZ/ZN7Y16nQRi -z1xBcjZyCUUa668g0VrI5Z1NNWZ0/gbaLVTHduEli6GM/H/NgKxS67JfRXzJ9onl -d6vrK+xmeHyA7QSOieEDettaNCvm+HjU8mmOb4F1pCNZktDrch5rI8EzQlmFQuq4 -y50YLRZGSlK1QLjzMnT//oaP7mHjN/inzZTHBvTzhU2OjcjzEW7l4ry224Sdu/eH -lhEnNk2eq+mH/yESkn3sJcmH4uYIXh8Dyvcy/uVkPQKBgQDzSC89qxT4sls9n0sL -0DfVhq1D7kEXggD/4wNA714N24N/NWi5BYUDZVh9Kxqy9SuWlFYg1L1ZNZHB02aV -GJdEiFMFgRea2E5NHnhWop+qYPq5N9jD72MHmz/6swX9VGi1p5DqjzK2hWMgoih9 -4ky1zxMw+P+aDaQ6xwZF1nr+mwKBgQDIFKTvaJYjqQ/lzRMIPLA3sg6RQ+Mqwt/C -BZ9Oc3DGtuglV8F73i7ML2Ptg0GtVZo3NJgGzMerpNvEoc1pDCuZkzSYitcYysQQ -wsailMQFCv9jJ9g28lSGKlEPYhcLejH8ZRi8jH0fObHIvgr7komNvvPIDFnw/uR8 -WsgrloD1cwKBgAdlAkqVkKWehjdxSA6r3YaX+Vw/OatFQFKGy+qFXA5/xZdwQCaf -jFN2GSJ01PLrkM+a4qNM1BSKFEwX6N5PSQnEOwHH0rfaK0cczfuUJdY/7F8E24nZ -FOF+TouINX5lumkLFtSKVbhGhaTQSPrKjhpYmPS8HMjJ8Vv4ALDOvB5RAoGBAJAS -RX3bCpmdCESKOdUplh5UyaaSgsZs0qCsWb0s5R1B4cHaAgnGwF3pFgSWCjndNRHh -fkMPPAv9xv49IGMvD0ojtLDO8Pn6L9p91niFtOyIscNdkpRmRLTjTcFM+ZkbIVlE -Ft7WLtbIPZt2NQRXzVLTGEmJk040zKQ63n58flm/AoGBAKt97WLeHB9S/q0dpEGX -Qk+1BXRAH0/4wK9lNrSeaw+npFr8rNN9K3sIBC/XnOwhT+wbKBpOoBT3PNHbNxVr -EPPQ/pPmZ1TcHc7bszJnZon2S2PFJRDN4601X1/eFoTvakBnLlt1096paaolSmCG -nYED9qXuh2VzUU1GgcqPXgf/ +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9CWMRLMXo1CF +/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 +kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS +wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM +jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT +Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt +OzboKgs1AgMBAAECggEBAKLj6IOJBKXolczpzb8UkyAjAkGBektcseV07gelJ/fk +3z0LuWPv5p12E/HlXB24vU2x/ikUbbP3eMsawRzDEahQqmNmPEkYAYUAy/Qpi9GN +DYvn3LqDec4jVgeQKS+p9H2DzUpTogp8zR2//yzbuWBg2+F//xh7vU0S0RQCziPM +x7RSBgbhxSfChfEJbS2sDnzfh0jRQmoY95iFv7puet1FJtzdZ4fgCd1RqmC2lFM5 +H0eZtN/Cz19lieVs0b996DErdEBqClVZO00eYbRozCDaBzRU3ybB/dMrGJxhkkXm +wb3kWMtziH9qOYsostuHIFu8eKFLloKxFnq2R4DGxOECgYEA2KUIZISOeGJSBcLJ +JAUK2gvgXPNo4HHWIwOA9xeN3ZJlsnPlffXQNnm6t1st1V2gfMm9I2n0m/F0y2B/ +n/XGSa8bghfPA9l0c2h58lkL3JQJR/paa8ycTz+YZPrznEyN7Qa0RrJXUvZv9lQL +Hc3+FHcSHgMqDV2f2bHAEu9YGi0CgYEAx6VEIPNvrHFgjo/jk1RTuk+m0xEWQsZL +Cs+izQMr2TaeJn8LG+93AvFuYn0J0nT3WuStLPrUg8i4IhSS6lf1tId5ivIZPm4r +YwMyblBJXhnHbk7Uqodjfw/3s6V2HAu++B7hTdyVr9DFuST9uv4m8bkPV8rfX1jE +I2rAPVWvgikCgYB+wNAQP547wQrMZBLbCDg5KwmyWJfb+b6X7czexOEz6humNTjo +YZHYzY/5B1fhpk3ntQD8X1nGg5caBvOk21+QbOtjShrM3cXMYCw5JvBRtitX+Zo9 +yBEMLOE0877ki8XeEDYZxu5gk98d+D4oygUGZEQtWxyXhVepPt5qNa8OYQKBgQDH +RVgZI6KFlqzv3wMh3PutbS9wYQ+9GrtwUQuIYe/0YSW9+vSVr5E0qNKrD28sV39F +hBauXLady0yvB6YUrjMbPFW+sCMuQzyfGWPO4+g3OrfqjFiM1ZIkE0YEU9Tt7XNx +qTDtTI1D7bhNMnTnniI1B6ge0und+3XafAThs5L48QKBgQCTTpfqMt8kU3tcI9sf +0MK03y7kA76d5uw0pZbWFy7KI4qnzWutCzb+FMPWWsoFtLJLPZy//u/ZCUVFVa4d +0Y/ASNQIESVPXFLAltlLo4MSmsg1vCBsbviEEaPeEjvMrgki93pYtd/aOSgkYC1T +mEq154s5rmqh+h+XRIf7Au0SLw== -----END PRIVATE KEY----- diff --git a/hyper-boring/test/root-ca.pem b/hyper-boring/test/root-ca.pem new file mode 100644 index 00000000..4ec2f538 --- /dev/null +++ b/hyper-boring/test/root-ca.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G +ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV +eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr +7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 +aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc +klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN +XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn +BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv +Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 +AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy +OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 +mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 +GA== +-----END CERTIFICATE----- From ae37df73c42f5af9d9a5d0a728cf090be2d679c4 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 20 Dec 2023 19:56:43 +0100 Subject: [PATCH 04/22] Introduce HttpsLayer::set_ssl_callback This lets us customize the Ssl of each connection, like set_callback which lets us customize the ConnectConfiguration a step earlier. --- hyper-boring/src/lib.rs | 54 +++++++++++++++++++++++++++++++++------- hyper-boring/src/test.rs | 6 +++-- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/hyper-boring/src/lib.rs b/hyper-boring/src/lib.rs index d6e82c1b..f1c416bf 100644 --- a/hyper-boring/src/lib.rs +++ b/hyper-boring/src/lib.rs @@ -7,7 +7,8 @@ use antidote::Mutex; use boring::error::ErrorStack; use boring::ex_data::Index; use boring::ssl::{ - ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslSessionCacheMode, + ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, + SslSessionCacheMode, }; use http::uri::Scheme; use hyper::client::connect::{Connected, Connection}; @@ -41,14 +42,16 @@ fn key_index() -> Result, ErrorStack> { struct Inner { ssl: SslConnector, cache: Arc>, - #[allow(clippy::type_complexity)] - callback: Option< - Arc Result<(), ErrorStack> + Sync + Send>, - >, + callback: Option, + ssl_callback: Option, } +type Callback = + Arc Result<(), ErrorStack> + Sync + Send>; +type SslCallback = Arc Result<(), ErrorStack> + Sync + Send>; + impl Inner { - fn setup_ssl(&self, uri: &Uri, host: &str) -> Result { + fn setup_ssl(&self, uri: &Uri, host: &str) -> Result { let mut conf = self.ssl.configure()?; if let Some(ref callback) = self.callback { @@ -69,7 +72,13 @@ impl Inner { let idx = key_index()?; conf.set_ex_data(idx, key); - Ok(conf) + let mut ssl = conf.into_ssl(host)?; + + if let Some(ref ssl_callback) = self.ssl_callback { + ssl_callback(&mut ssl, uri)?; + } + + Ok(ssl) } } @@ -117,17 +126,30 @@ impl HttpsLayer { ssl: ssl.build(), cache, callback: None, + ssl_callback: None, }, }) } /// Registers a callback which can customize the configuration of each connection. + /// + /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), + /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] + /// instead. pub fn set_callback(&mut self, callback: F) where F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, { self.inner.callback = Some(Arc::new(callback)); } + + /// Registers a callback which can customize the `Ssl` of each connection. + pub fn set_ssl_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.ssl_callback = Some(Arc::new(callback)); + } } impl Layer for HttpsLayer { @@ -182,12 +204,24 @@ where } /// Registers a callback which can customize the configuration of each connection. + /// + /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), + /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] + /// instead. pub fn set_callback(&mut self, callback: F) where F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, { self.inner.callback = Some(Arc::new(callback)); } + + /// Registers a callback which can customize the `Ssl` of each connection. + pub fn set_ssl_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.ssl_callback = Some(Arc::new(callback)); + } } impl Service for HttpsConnector @@ -244,8 +278,10 @@ where } } - let config = inner.setup_ssl(&uri, host)?; - let stream = tokio_boring::connect(config, host, conn).await?; + let ssl = inner.setup_ssl(&uri, host)?; + let stream = tokio_boring::SslStreamBuilder::new(ssl, conn) + .connect() + .await?; Ok(MaybeHttpsStream::Https(stream)) }; diff --git a/hyper-boring/src/test.rs b/hyper-boring/src/test.rs index e1b30f07..006d5163 100644 --- a/hyper-boring/src/test.rs +++ b/hyper-boring/src/test.rs @@ -139,9 +139,11 @@ async fn alpn_h2() { let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); ssl.set_ca_file("test/root-ca.pem").unwrap(); - ssl.set_alpn_protos(b"\x02h2\x08http/1.1").unwrap(); - let ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); + let mut ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); + + ssl.set_ssl_callback(|ssl, _| ssl.set_alpn_protos(b"\x02h2\x08http/1.1")); + let client = Client::builder().build::<_, Body>(ssl); let resp = client From 12451541d3a55e47280fd7e2b166b853c9d94a34 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 2 Jan 2024 15:31:33 +0100 Subject: [PATCH 05/22] Rearrange imports in x509 module --- boring/src/x509/store.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/boring/src/x509/store.rs b/boring/src/x509/store.rs index 7033450a..885df975 100644 --- a/boring/src/x509/store.rs +++ b/boring/src/x509/store.rs @@ -40,14 +40,13 @@ //! let store: X509Store = builder.build(); //! ``` -use crate::ffi; -use foreign_types::{ForeignType, ForeignTypeRef}; -use std::mem; - use crate::error::ErrorStack; +use crate::ffi; use crate::stack::StackRef; use crate::x509::{X509Object, X509}; use crate::{cvt, cvt_p}; +use foreign_types::{ForeignType, ForeignTypeRef}; +use std::mem; foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; @@ -105,8 +104,6 @@ foreign_type_and_impl_send_sync! { impl X509StoreRef { /// Get a reference to the cache of certificates in this store. pub fn objects(&self) -> &StackRef { - unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) } + unsafe { StackRef::from_ptr(ffi::X509_STORE_get0_objects(self.as_ptr())) } } } - -use crate::ffi::X509_STORE_get0_objects; From dfd54746d769f9dbe76f9671e8100477ccc9b561 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 3 Jan 2024 13:56:07 +0100 Subject: [PATCH 06/22] Move x509 tests to a subdirectory --- boring/src/x509/{tests.rs => tests/mod.rs} | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) rename boring/src/x509/{tests.rs => tests/mod.rs} (91%) diff --git a/boring/src/x509/tests.rs b/boring/src/x509/tests/mod.rs similarity index 91% rename from boring/src/x509/tests.rs rename to boring/src/x509/tests/mod.rs index e656873d..cba4c7df 100644 --- a/boring/src/x509/tests.rs +++ b/boring/src/x509/tests/mod.rs @@ -21,7 +21,7 @@ fn pkey() -> PKey { #[test] fn test_cert_loading() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); @@ -33,7 +33,7 @@ fn test_cert_loading() { #[test] fn test_debug() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let debugged = format!("{:#?}", cert); @@ -47,7 +47,7 @@ fn test_debug() { #[test] fn test_cert_issue_validity() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let not_before = cert.not_before().to_string(); let not_after = cert.not_after().to_string(); @@ -58,7 +58,7 @@ fn test_cert_issue_validity() { #[test] fn test_save_der() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let der = cert.to_der().unwrap(); @@ -67,7 +67,7 @@ fn test_save_der() { #[test] fn test_subject_read_cn() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap(); @@ -76,7 +76,7 @@ fn test_subject_read_cn() { #[test] fn test_nid_values() { - let cert = include_bytes!("../../test/nid_test_cert.pem"); + let cert = include_bytes!("../../../test/nid_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); @@ -95,7 +95,7 @@ fn test_nid_values() { #[test] fn test_nameref_iterator() { - let cert = include_bytes!("../../test/nid_test_cert.pem"); + let cert = include_bytes!("../../../test/nid_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let mut all_entries = subject.entries(); @@ -122,7 +122,7 @@ fn test_nameref_iterator() { #[test] fn test_nid_uid_value() { - let cert = include_bytes!("../../test/nid_uid_test_cert.pem"); + let cert = include_bytes!("../../../test/nid_uid_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); @@ -132,7 +132,7 @@ fn test_nid_uid_value() { #[test] fn test_subject_alt_name() { - let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = include_bytes!("../../../test/alt_name_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); @@ -149,7 +149,7 @@ fn test_subject_alt_name() { #[test] fn test_subject_alt_name_iter() { - let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = include_bytes!("../../../test/alt_name_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); @@ -342,7 +342,7 @@ fn x509_req_builder() { #[test] fn test_stack_from_pem() { - let certs = include_bytes!("../../test/certs.pem"); + let certs = include_bytes!("../../../test/certs.pem"); let certs = X509::stack_from_pem(certs).unwrap(); assert_eq!(certs.len(), 2); @@ -358,9 +358,9 @@ fn test_stack_from_pem() { #[test] fn issued() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - let ca = include_bytes!("../../test/root-ca.pem"); + let ca = include_bytes!("../../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); assert_eq!(ca.issued(&cert), Ok(())); @@ -369,7 +369,7 @@ fn issued() { #[test] fn signature() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let signature = cert.signature(); assert_eq!( @@ -390,16 +390,16 @@ fn signature() { #[test] #[allow(clippy::redundant_clone)] fn clone_x509() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); drop(cert.clone()); } #[test] fn test_verify_cert() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - let ca = include_bytes!("../../test/root-ca.pem"); + let ca = include_bytes!("../../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); let chain = Stack::new().unwrap(); @@ -418,9 +418,9 @@ fn test_verify_cert() { #[test] fn test_verify_fails() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - let ca = include_bytes!("../../test/alt_name_cert.pem"); + let ca = include_bytes!("../../../test/alt_name_cert.pem"); let ca = X509::from_pem(ca).unwrap(); let chain = Stack::new().unwrap(); @@ -436,7 +436,7 @@ fn test_verify_fails() { #[test] fn test_save_subject_der() { - let cert = include_bytes!("../../test/cert.pem"); + let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let der = cert.subject_name().to_der().unwrap(); @@ -446,7 +446,7 @@ fn test_save_subject_der() { #[test] fn test_load_subject_der() { - // The subject from ../../test/cert.pem + // The subject from ../../../test/cert.pem const SUBJECT_DER: &[u8] = &[ 48, 90, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 65, 85, 49, 19, 48, 17, 6, 3, 85, 4, 8, 12, 10, 83, 111, 109, 101, 45, 83, 116, 97, 116, 101, 49, 33, 48, 31, 6, 3, 85, 4, 10, 12, 24, From 8e2597bbb432bceab8c17218b2b2a1cdcca730a5 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 3 Jan 2024 13:54:33 +0100 Subject: [PATCH 07/22] Introduce X509Flags For now it has a single associated constant, X509Flags::TRUSTED_FIRST. --- boring/src/ssl/mod.rs | 7 +- boring/src/x509/mod.rs | 12 ++- boring/src/x509/store.rs | 21 +++++ boring/src/x509/tests/mod.rs | 2 + boring/src/x509/tests/trusted_first.rs | 104 +++++++++++++++++++++++++ boring/src/x509/verify.rs | 35 ++++++++- boring/test/cert-with-intermediate.pem | 20 +++++ boring/test/intermediate-ca.key | 27 +++++++ boring/test/intermediate-ca.pem | 21 +++++ boring/test/root-ca-2.key | 27 +++++++ boring/test/root-ca-2.pem | 20 +++++ boring/test/root-ca-cross.pem | 21 +++++ 12 files changed, 314 insertions(+), 3 deletions(-) create mode 100644 boring/src/x509/tests/trusted_first.rs create mode 100644 boring/test/cert-with-intermediate.pem create mode 100644 boring/test/intermediate-ca.key create mode 100644 boring/test/intermediate-ca.pem create mode 100644 boring/test/root-ca-2.key create mode 100644 boring/test/root-ca-2.pem create mode 100644 boring/test/root-ca-cross.pem diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index d7299f99..ead1e06b 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -3176,7 +3176,7 @@ impl SslRef { /// This corresponds to [`SSL_get0_param`]. /// /// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html - pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { + pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { #[cfg(feature = "rpk")] assert!( !self.ssl_context().is_rpk(), @@ -3186,6 +3186,11 @@ impl SslRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } } + /// See [`Self::verify_param_mut`]. + pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { + self.verify_param_mut() + } + /// Returns the certificate verification result. /// /// This corresponds to [`SSL_get_verify_result`]. diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index 10ee1935..5140841b 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -7,7 +7,6 @@ //! Internet protocols, including SSL/TLS, which is the basis for HTTPS, //! the secure protocol for browsing the web. -use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long, c_void}; use std::convert::TryInto; @@ -30,12 +29,14 @@ use crate::bio::MemBioSlice; use crate::conf::ConfRef; use crate::error::ErrorStack; use crate::ex_data::Index; +use crate::ffi; use crate::hash::{DigestBytes, MessageDigest}; use crate::nid::Nid; use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; use crate::ssl::SslRef; use crate::stack::{Stack, StackRef, Stackable}; use crate::string::OpensslString; +use crate::x509::verify::X509VerifyParamRef; use crate::{cvt, cvt_n, cvt_p}; pub mod extension; @@ -147,6 +148,15 @@ impl X509StoreContextRef { } } + /// Returns a mutable reference to the X509 verification configuration. + /// + /// This corresponds to [`X509_STORE_CTX_get0_param`]. + /// + /// [`SSL_get0_param`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_CTX_get0_param.html + pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { + unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_CTX_get0_param(self.as_ptr())) } + } + /// Verifies the stored certificate. /// /// Returns `true` if verification succeeds. The `error` method will return the specific diff --git a/boring/src/x509/store.rs b/boring/src/x509/store.rs index 885df975..ee3fb52f 100644 --- a/boring/src/x509/store.rs +++ b/boring/src/x509/store.rs @@ -43,6 +43,7 @@ use crate::error::ErrorStack; use crate::ffi; use crate::stack::StackRef; +use crate::x509::verify::{X509Flags, X509VerifyParamRef}; use crate::x509::{X509Object, X509}; use crate::{cvt, cvt_p}; use foreign_types::{ForeignType, ForeignTypeRef}; @@ -91,6 +92,26 @@ impl X509StoreBuilderRef { pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) } } + + /// Sets verify flags. + /// + /// This corresponds to [`X509_STORE_set_flags`]. + /// + /// [`X509_STORE_set_flags`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_set_flags.html + pub fn set_flags(&mut self, flags: X509Flags) { + unsafe { + ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits()); + } + } + + /// Returns a mutable reference to the X509 verification configuration. + /// + /// This corresponds to [`X509_STORE_get0_param`]. + /// + /// [`SSL_get0_param`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_get0_param.html + pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { + unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_get0_param(self.as_ptr())) } + } } foreign_type_and_impl_send_sync! { diff --git a/boring/src/x509/tests/mod.rs b/boring/src/x509/tests/mod.rs index cba4c7df..65bb7f90 100644 --- a/boring/src/x509/tests/mod.rs +++ b/boring/src/x509/tests/mod.rs @@ -14,6 +14,8 @@ use crate::x509::extension::{ use crate::x509::store::X509StoreBuilder; use crate::x509::{X509Extension, X509Name, X509Req, X509StoreContext, X509}; +mod trusted_first; + fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); PKey::from_rsa(rsa).unwrap() diff --git a/boring/src/x509/tests/trusted_first.rs b/boring/src/x509/tests/trusted_first.rs new file mode 100644 index 00000000..951d1da5 --- /dev/null +++ b/boring/src/x509/tests/trusted_first.rs @@ -0,0 +1,104 @@ +//! See https://github.com/google/boringssl/blob/cc696073cffe7978d489297fbdeac4c0030384aa/crypto/x509/x509_test.cc#L3977-L3980 + +use crate::stack::Stack; +use crate::x509::store::X509StoreBuilder; +use crate::x509::verify::{X509Flags, X509VerifyParamRef}; +use crate::x509::{X509Ref, X509StoreContext, X509VerifyError, X509VerifyResult, X509}; + +#[test] +fn test_verify_cert() { + let root2 = X509::from_pem(include_bytes!("../../../test/root-ca-2.pem")).unwrap(); + let root1 = X509::from_pem(include_bytes!("../../../test/root-ca.pem")).unwrap(); + let root1_cross = X509::from_pem(include_bytes!("../../../test/root-ca-cross.pem")).unwrap(); + let intermediate = X509::from_pem(include_bytes!("../../../test/intermediate-ca.pem")).unwrap(); + let leaf = X509::from_pem(include_bytes!("../../../test/cert-with-intermediate.pem")).unwrap(); + + assert_eq!(Ok(()), verify(&leaf, &[&root1], &[&intermediate], |_| {})); + + #[cfg(not(feature = "fips"))] + assert_eq!( + Ok(()), + verify( + &leaf, + &[&root1, &root2], + &[&intermediate, &root1_cross], + |_| {} + ) + ); + + #[cfg(feature = "fips")] + assert_eq!( + Err(X509VerifyError::CERT_HAS_EXPIRED), + verify( + &leaf, + &[&root1, &root2], + &[&intermediate, &root1_cross], + |_| {} + ) + ); + + assert_eq!( + Ok(()), + verify( + &leaf, + &[&root1, &root2], + &[&intermediate, &root1_cross], + |param| param.set_flags(X509Flags::TRUSTED_FIRST), + ) + ); + + assert_eq!( + Err(X509VerifyError::CERT_HAS_EXPIRED), + verify( + &leaf, + &[&root1, &root2], + &[&intermediate, &root1_cross], + |param| param.clear_flags(X509Flags::TRUSTED_FIRST), + ) + ); + + assert_eq!( + Ok(()), + verify(&leaf, &[&root1], &[&intermediate, &root1_cross], |param| { + param.clear_flags(X509Flags::TRUSTED_FIRST) + },) + ); +} + +fn verify( + cert: &X509Ref, + trusted: &[&X509Ref], + untrusted: &[&X509Ref], + configure: impl FnOnce(&mut X509VerifyParamRef), +) -> X509VerifyResult { + let trusted = { + let mut builder = X509StoreBuilder::new().unwrap(); + + for cert in trusted { + builder.add_cert((**cert).to_owned()).unwrap(); + } + + builder.build() + }; + + let untrusted = { + let mut stack = Stack::new().unwrap(); + + for cert in untrusted { + stack.push((**cert).to_owned()).unwrap(); + } + + stack + }; + + let mut store_ctx = X509StoreContext::new().unwrap(); + + let _ = store_ctx.init(&trusted, cert, &untrusted, |ctx| { + configure(ctx.verify_param_mut()); + ctx.verify_cert().unwrap(); + + Ok(()) + }); + + store_ctx.verify_result() +} diff --git a/boring/src/x509/verify.rs b/boring/src/x509/verify.rs index decc3092..7ea4ddeb 100644 --- a/boring/src/x509/verify.rs +++ b/boring/src/x509/verify.rs @@ -1,6 +1,6 @@ use crate::ffi; use foreign_types::ForeignTypeRef; -use libc::c_uint; +use libc::{c_uint, c_ulong}; use std::net::IpAddr; use crate::cvt; @@ -24,6 +24,14 @@ bitflags! { } } +bitflags! { + /// Flags used to check an `X509` certificate. + #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)] + pub struct X509Flags: c_ulong { + const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST as _; + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::X509_VERIFY_PARAM; fn drop = ffi::X509_VERIFY_PARAM_free; @@ -33,6 +41,31 @@ foreign_type_and_impl_send_sync! { } impl X509VerifyParamRef { + /// Set flags. + /// + /// This corresponds to [`X509_VERIFY_PARAM_set_flags`]. + /// + /// [`X509_VERIFY_PARAM_set_flags`]: https://www.openssl.org/docs/man3.2/man3/X509_VERIFY_PARAM_set_flags.html + pub fn set_flags(&mut self, flags: X509Flags) { + unsafe { + ffi::X509_VERIFY_PARAM_set_flags(self.as_ptr(), flags.bits()); + } + } + + /// Clear flags. + /// + /// Useful to clear out default flags, such as `X509Flags::TRUSTED_FIRST` when the fips feature is off. + /// + /// This corresponds to [`X509_VERIFY_PARAM_clear_flags`]. + /// + /// [`X509_VERIFY_PARAM_set_flags`]: https://www.openssl.org/docs/man3.2/man3/X509_VERIFY_PARAM_set_flags.html + pub fn clear_flags(&mut self, flags: X509Flags) { + unsafe { + ffi::X509_VERIFY_PARAM_clear_flags(self.as_ptr(), flags.bits()); + } + } + + /// /// Set the host flags. /// /// This corresponds to [`X509_VERIFY_PARAM_set_hostflags`]. diff --git a/boring/test/cert-with-intermediate.pem b/boring/test/cert-with-intermediate.pem new file mode 100644 index 00000000..77c24317 --- /dev/null +++ b/boring/test/cert-with-intermediate.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMzCCAhsCFBEiNxpuknaO7Pw1Yi88UW4aiGo0MA0GCSqGSIb3DQEBCwUAMFIx +CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMS4wLAYDVQQKDCVJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQgSW50ZXJtZWRpYXRlMB4XDTI0MDEwMzE0MjIz +MFoXDTI2MDgxMjE0MjIzMFowWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUt +U3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UE +AwwKZm9vYmFyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKj0 +JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub3mw2/Ja5BD/yN96/7zMSumXF8uS3Skmp +yiJkbyD01TSRTqjlP7/VCBlyUIChlpLQmrGaijZiT/VCyPXqmcwFzXS5IOTpX1ol +JfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS +1ieT2asFsAyOZqWhk2fakwwBDFWDhOGIubfO+5aq9cBJbNRlzsgB3UZs3gC0O6Gz +bnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4YeuZkkbHTFBMz288PUc3m3ZTcpN+E7+ZO +UBRZXKD20K07NugqCzUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEANWlOvyLEHdPV +8rMdfqLTZZyA79L1N3bP1FWS97fF36Y9EnTKChenwkBob1abY4jQ2/LICKND+ux8 +xDlmMlYRH4aM5bXAjOcdpmq9R9SuzsK/2m79xONF//AX4zb0s5b+QEwdYkfJ5jiO +xMrnatwHQhFvQIQvuTo2o0WZEnkubNYDxVh7UOv9cOQjwm0+58CIEG5SHR9grG5u +TTswu7DswgpfSCKKPaFCF4pWxLfryYwadO0/4Ot/ZbElbAdJYC8CI1QC14knk2cD +0ZG9jaVPP9wCAt/ZIu8NbsZN7DNbISaXVfMju+xSdey8B3FLRkLq9TKmnLum5LR2 +TyM6hDIh8A== +-----END CERTIFICATE----- diff --git a/boring/test/intermediate-ca.key b/boring/test/intermediate-ca.key new file mode 100644 index 00000000..8012c9a6 --- /dev/null +++ b/boring/test/intermediate-ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEApyZi0joAIH8M7GaitH27lQs1XZaXwv5PI9bIeSkIX4BafIcU +I7hdPLreJoP6EsuoswXyhgZU8FQvNRjMAGPzvVviG+vY/l6jFI+JqW7Pphr35QJO +jqxwW/K/wYei0FS6C3SF+CJ2yIgG4YlJM9Hoq/EpfIxmyuZ2yHD/JiQ5kxNP7vKT +77f7k5zpCVG1kiQZKQT4iysQDz2e1ozi3W7NCDqnvM9+EX1DREiCqRUwuzIuTlkA +Z+8HpET5wS2Pm5uJQXDCid0slYMcuOL6JoHekbs69wkt4powcPPhXWoTCyUjpqsx +w0KPiBzViJUsd8JUq8ge+jVqP2pzvkQk4BWTMwIDAQABAoIBAFBiEHIjPH5kOzXQ +4fxE3xn9KuvYCSHYJP0KRJyn1AQBeQKb/15yQjx7bWw+WdwCHx4BBTHZB64P/ifd +xfWGG+h7sJBW6qLhpjG0GbLmvGuYWpDCfD72xI4jfn42mWDw7gumPOsov9EOQaji +2dZW4zsVHitsZd672HHqjXmtQBbvEcm/cuPoL2/s9crKwHbF90kb9BOYcz+/U138 +zPfXFM5AbivpiQHA7CmMrQ833op42fQCfrxGs1XkZPO30EPpCtmHE6+Xhv+GGWp/ +EF7D6pwkT4OElgzAP6cthPqZOtQLE2LCM/mTy/cFRtrBjKPlZ/UBrxjaLI1FHoAk +TYX81GECgYEA451EWFCrX5vWEMJE7zCALiQbxxOhQCIEufvkxUvDnsqjTPj/ylpZ +usu+YC5BcgwVxjso8dEL8pcd8pAFVLeX8wBDeGfTdhUmPPZmx8ViFbZTVq/Tz+Jw +tHo0foq8gfTLJrvdzuyFEHR6z5O16EtKOa+G1gIF/atV8hO/oRXLXvECgYEAu/7B +SpzbBJoxame27uaakYYVKuAD2wVAmfP9XuTV6IvE845sgmzTYURxSnO0RZCuNj5x +7u//HdGoFuA3o4Un4XLx1qot2op9ql1xuD/V3aqrvhpzvoCklks6t+PW3/Sef6TH +21TOCahpoQqD/UrSrHEJXC7lmkfcPCir3QflnGMCgYBV2AFnwXzwwShaB7rR7xvY +yxuC2H9vXaUks8DTPEDaCZjPNfXaznqa/a6ePbPHHJG1wqgtk2cLJj1QN0sbaWaw +akAIEDhrh4x1X4TiASp9/9askgGznLZfCtvzgcWYycc4o5ADM6b3zsZmtVHc+1BS +M0YKPpcd1dnDQ/l4+mxKMQKBgQCenCB+j/plVqaMjLaVty//yW2AgAIgvryzZ1yE +vHMRQSNJDgfUvnZVIUaoNxiIfLnPAD5mBkxq3yF/M2sd5lEwcCdEIs6PDLtbin1Q +o2MQI1fFC1JODwFN4GjJD0ySJTO4o9EO5uzyzwlXmqSjhoZagQARq2uCEFDq3LGr +yWba2wKBgDT+5qjFweI5RmE1pDvUH9gOPNflyOpyjnbueunmTn1rzcRhx9xgM3QB +ehWCRR1Y/vAnu5uupf0rG/Y/gtvIVyC3F+0csNox7T9e0t4sdgORYOVWbvsIF2t9 +2HYjY782ws3EBF5yNKJDgV2sNjA0Wpb6lahkxRut314jnwGplR2w +-----END RSA PRIVATE KEY----- diff --git a/boring/test/intermediate-ca.pem b/boring/test/intermediate-ca.pem new file mode 100644 index 00000000..cdbf77ce --- /dev/null +++ b/boring/test/intermediate-ca.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgIUE+pcEHU5e4wkMpp2qoyHy+wH8aMwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAxMDMxMDM0MDdaFw0yNjA4 +MTIxMDM0MDdaMFIxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMS4w +LAYDVQQKDCVJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQgSW50ZXJtZWRpYXRlMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApyZi0joAIH8M7GaitH27lQs1 +XZaXwv5PI9bIeSkIX4BafIcUI7hdPLreJoP6EsuoswXyhgZU8FQvNRjMAGPzvVvi +G+vY/l6jFI+JqW7Pphr35QJOjqxwW/K/wYei0FS6C3SF+CJ2yIgG4YlJM9Hoq/Ep +fIxmyuZ2yHD/JiQ5kxNP7vKT77f7k5zpCVG1kiQZKQT4iysQDz2e1ozi3W7NCDqn +vM9+EX1DREiCqRUwuzIuTlkAZ+8HpET5wS2Pm5uJQXDCid0slYMcuOL6JoHekbs6 +9wkt4powcPPhXWoTCyUjpqsxw0KPiBzViJUsd8JUq8ge+jVqP2pzvkQk4BWTMwID +AQABo1AwTjAdBgNVHQ4EFgQUZ3ELefSmoenETTa39CQwVzdoLZcwHwYDVR0jBBgw +FoAUbNOlA6sNXyzJjYqciKeId7g3/ZowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAQEAHCXvCU1XQM5a7hhgrMcKQRto9GEVIljnPv5H7x+wPvCfR1By/kzI +fsl+hA1q02ymLtOW16aq4si4exsQl4SktC+5hyhu0yOCevRYXCcrh5NrNbwTFnK/ +LIP4dRz4XBxC9pYg0rqvo+v64at6EBTXxYfBHo9Cj0QuZIJoYmGEOojdE0PudZdc +b1iuXk9FZlUueFq8uSkHD7EpxonPS9iWQA5dbw1Q+0hWqvA/npAvFXBHkF/Jyaht +fpqoUrr4LYUr/ShC1IVHG7TAEElnOGz0dY6uxkr1B6YxBvCJ6gesk2cJBC1i3g9I +9xvt4zxQNQynX0IHcar8xfgZqD4ZdWQY0w== +-----END CERTIFICATE----- diff --git a/boring/test/root-ca-2.key b/boring/test/root-ca-2.key new file mode 100644 index 00000000..aab48239 --- /dev/null +++ b/boring/test/root-ca-2.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAwSgPW00nGOTje0FHm1HXT3ANHjW3HGPbxiMSRvSoBEdv8R9e +0PoKjse0xQsa5nKolbUhJBS6dkH+13VPOs6e+vZyXD6OYQfi2e42Mw0SPFl5g2qU +fy/17q3ipqPJnT6YHhGpx/P91F7yjDAF2MvNRGQ/6AYWD4MUr6+5vPHEYhQ/JlAK +cN/uWUM+bg2mwMNpmuGRV1tg0hKl9nT1fX1i6OSszPLIY1dC0eHv2gRh1unrXNoY +A76xohiwcJYAAPjrx167S8td8gmWnOwYnCnGIw2ceNpEQv4/bEvtKiLGOu4HUO/x +a7emy1QZgJth5TqQf0pwPEJC0mV5LFoXtlOpjwIDAQABAoIBAB3xBshhYlEikfy2 +NtJl0ll3BiGLtBHLjPLe1uN242CebkTTVxBP4jkVzfjJaucUGPvz8uoz6F+ShV2C +ysBT7SL79uhDrjBuV4TuvyoUuaHvQL3VVKWOmrHf9IVeWE9ut4fZtxbOxKcZ/MEs +ZIuhs/UJETr3To4jBJ7jP4iBda66LXeGDwnhia04zpFWwRRyRFvdVwTvMm9TN2GY +21J6rnc44bGQ/l0qsxSrv/OuW3ZmFNz85mRbuLswgawJgjMSlt1orLz5mdofDxlz +898nSrpJq/mAj8kgV+sH2jGv5FVZrv30W/0GlXObiJLhJiywYkpXbSn/H//w9+ij +ItQXjDECgYEA9RNootH8F0vuWVezKrt9ApE+8AzwltDgMlFc/HEjINnKFg7SWsSN +oinPVcQ07PS+2E7Fgv/6IFv/RTATGIPYrNWGE17dR8xmwh+Xrexz45c49cHTwVCF +VM2J0PvlcEEAscMe1bd5HqIOJm+hvvqfwWdacUPZgtsaS9F/e33vj0cCgYEAycQx +c5EQ9T82z+qMhQ/mf63kYMYDsHbv6F92Pt38V24yh8NTW5lEcV+NonDFrPVH5Vd3 +gU1lvXnG8e3Aj6EXOeEzfu9dpfdyqyZXIU2hbRPYuha+goBd03pM8+YEIgJX3ktu +1Q+G6uMrSLVbe+l06OEcYmvj8xGNWrk/3+ZiB3kCgYEA15+c92xjLSgcbDTyKU3O +Pj0Gr/Pilf7u0ratZlowew3DdMbToxK+PogkqKQ5oKXxZ6Vet9R6AJCQtxIGKxKN +x/sRvOdBL5OScYeUT2zzxbFeZzODGNm8hZFViS6nfq1ibARtk8Gaai5Q3tZm6/3c +IzDI7VCyBiS6LS0EyeVSqa8CgYBRmM6G9jvtcssv+qMpjOyi5iheGraTPwZ262Re +uFe85Av7a7riaHGNiB83enP3JpsU3PKvkCV9IyqZ3JTrgTJrbe/tfdBZtmDhZngG +N+b4vfYADAKvtEo9pFBKstMpDdmLROZltAnUJFr05KNC0X8+Twuzof5l5stLzW9P +lVQ/wQKBgQDT4ixRRx4DlMMzBXNRTkUuZloEhZtLC5xj71KhE7OeOdJ0e6DHJMg3 +VDVQk+y3Qc+8Hh9yxMK/zrYLdHSVyvHTk+7AbppLGX7ZtyLm/gVq3l3VjWKmXKbm +ZT+3+2gqVyjr/p69T7/aLexvfzU5LdjwO7SQFNB4qZaG74WpGAlkMg== +-----END RSA PRIVATE KEY----- diff --git a/boring/test/root-ca-2.pem b/boring/test/root-ca-2.pem new file mode 100644 index 00000000..3b4deaf6 --- /dev/null +++ b/boring/test/root-ca-2.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSzCCAjOgAwIBAgIUOQyKTQXHMKXZgwc5iktVZkL7hfwwDQYJKoZIhvcNAQEL +BQAwRzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxIzAhBgNVBAoM +GkludGVybmV0IFdpZGdpdHMgUHR5IEx0ZCAyMB4XDTIzMTIwNDEwMzA0N1oXDTIz +MTIxNDEwMzA0N1owRzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +IzAhBgNVBAoMGkludGVybmV0IFdpZGdpdHMgUHR5IEx0ZCAyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwSgPW00nGOTje0FHm1HXT3ANHjW3HGPbxiMS +RvSoBEdv8R9e0PoKjse0xQsa5nKolbUhJBS6dkH+13VPOs6e+vZyXD6OYQfi2e42 +Mw0SPFl5g2qUfy/17q3ipqPJnT6YHhGpx/P91F7yjDAF2MvNRGQ/6AYWD4MUr6+5 +vPHEYhQ/JlAKcN/uWUM+bg2mwMNpmuGRV1tg0hKl9nT1fX1i6OSszPLIY1dC0eHv +2gRh1unrXNoYA76xohiwcJYAAPjrx167S8td8gmWnOwYnCnGIw2ceNpEQv4/bEvt +KiLGOu4HUO/xa7emy1QZgJth5TqQf0pwPEJC0mV5LFoXtlOpjwIDAQABoy8wLTAd +BgNVHQ4EFgQU1rQttC2Y2T0HZAjzRkacyFLVBr8wDAYDVR0TBAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAQEAsVucQLIzAKHwN/4ZuVOPpfy/B3+i/Stu2tvNhBxWpbh9 +RQTa0ylpDfaAOLr+TfxCyT0/NmblK4QWxN6AJ5AZS9fVnstLhInafv7So0n3LCg5 +eQkVcQtMdwHucfMw/iz7r229mOHBbK6cnZhu72rcnn7N/RlU+iEucfi6jO+r9iD1 +y20glRta+wEqIBg7nGhulOwwdHVkX7ulpnXIqNCgNvU7/Mp7J+CxuWmeZKLvUQAh +D/gHs9kOPK4izN9QBrRwbiyTaD8G7kFlVWD1tPXrOhBdE1L4OJWvUDSfO0DKueIW +aQa2fFsR1iPuFX/jeTuPk5X2+u5eH4pXj13NEqKvOA== +-----END CERTIFICATE----- diff --git a/boring/test/root-ca-cross.pem b/boring/test/root-ca-cross.pem new file mode 100644 index 00000000..244ea4b9 --- /dev/null +++ b/boring/test/root-ca-cross.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDajCCAlKgAwIBAgIUSYINSQdbr8yzV186s/zQj+2zol8wDQYJKoZIhvcNAQEL +BQAwRzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxIzAhBgNVBAoM +GkludGVybmV0IFdpZGdpdHMgUHR5IEx0ZCAyMB4XDTI0MDEwMzEwMzUyM1oXDTI2 +MDgxMjEwMzUyM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAK1R1hZ+di25dZefXsXbmZ7VUmcg2KcwzQ/kti1H +Dun0QVoVf9Ss6MfthmabW7jBpnyN4gJ29AhU+Lgt5AZEEJV6JxgE0lcmhUxUfo6v +5XNEj/vQXe0gV4niFXiF5WNU75cCL49zbcPc1/rHEwOEl8R+jNKyr/YEzrm9rwjE +h3hdel/A0K+F7GbkK+wqe49SOGqjicmqeSU5eYo5hvHJ7tJ/vFHEZQc8vfXS1iRt +AHyN1USXVqRkzVWfdmhX390aStxf1iNoKd6ldcp0QCrr5p3Bgtyw72H3HNnYLHNT +ehX6vBiK5IEaG+ngXJJQx6dXdNty8K3vlWlQ0qNf/2O9lBcCAwEAAaNQME4wHQYD +VR0OBBYEFGzTpQOrDV8syY2KnIiniHe4N/2aMB8GA1UdIwQYMBaAFNa0LbQtmNk9 +B2QI80ZGnMhS1Qa/MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBALw+ +mUsLEoqk6eI4jGv5TPP56RPMRdI+wwmQ8+sQ4DIOzDErkIIQMtoP3aqU6kstHrfY +RZ2tJSWfKb9GcE2SL5VtHQCjSJLsE7f+fTpCFn41q0QMsXF22IOxT2eDvK4Kb496 +NVulV6DhsHmbSjo6kla9U3Zqv4WiqLTNj757j+YgmplZQNx8vT5HkPIUi20IxEKV +m6CtPa0M2c2Hl/Y9v006AHmaXnabGvwnLsK92NV0oQb6KnB0mxOrL8od765SF9T0 +OXiNK/2ilN2UB1ft16GI/tU+2N+sTmW9/+S5lExfG/S3qXJwc1l4OC9tH9CxOtYt +6Q+cAmgl6qxF3ltltCM= +-----END CERTIFICATE----- From c9f071df150c99bf4f0f975b5cbb6a7758c15be5 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 3 Jan 2024 19:39:59 +0100 Subject: [PATCH 08/22] Release 4.3.0 --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f6425f4c..5c6ff949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "4.2.0" +version = "4.3.0" repository = "https://github.com/cloudflare/boring" edition = "2021" @@ -19,9 +19,9 @@ tag-prefix = "" publish = false [workspace.dependencies] -boring-sys = { version = "4.2.0", path = "./boring-sys" } -boring = { version = "4.2.0", path = "./boring" } -tokio-boring = { version = "4.2.0", path = "./tokio-boring" } +boring-sys = { version = "4.3.0", path = "./boring-sys" } +boring = { version = "4.3.0", path = "./boring" } +tokio-boring = { version = "4.3.0", path = "./tokio-boring" } bindgen = { version = "0.68.1", default-features = false, features = ["runtime"] } cmake = "0.1.18" From ae65a3f9f82104857e7a09b48e7bf8dfafe24e8a Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 20 Dec 2023 13:13:28 +0100 Subject: [PATCH 09/22] Fix support for fips-link-precompiled This feature expects a recent boringssl checkout (such as the one found in boring-sys/deps/boringssl), so it should not be using the same bindings as the fips feature, which are based on boring-sys/deps/boringssl-fips, which is older and with a different API. --- boring/src/bio.rs | 4 ++-- boring/src/ssl/mod.rs | 16 +++++----------- boring/src/x509/mod.rs | 4 ++-- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/boring/src/bio.rs b/boring/src/bio.rs index adb119b8..55870ded 100644 --- a/boring/src/bio.rs +++ b/boring/src/bio.rs @@ -19,9 +19,9 @@ impl<'a> Drop for MemBioSlice<'a> { impl<'a> MemBioSlice<'a> { pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { - #[cfg(not(any(feature = "fips", feature = "fips-link-precompiled")))] + #[cfg(not(feature = "fips"))] type BufLen = isize; - #[cfg(any(feature = "fips", feature = "fips-link-precompiled"))] + #[cfg(feature = "fips")] type BufLen = libc::c_int; ffi::init(); diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index ead1e06b..91da2bbd 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -688,7 +688,7 @@ impl SslCurve { pub const X25519: SslCurve = SslCurve(ffi::NID_X25519); - #[cfg(not(any(feature = "fips", feature = "fips-link-precompiled")))] + #[cfg(not(feature = "fips"))] pub const X25519_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::NID_X25519Kyber768Draft00); #[cfg(feature = "pq-experimental")] @@ -1402,10 +1402,7 @@ impl SslContextBuilder { /// [`SSL_CTX_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { - #[cfg_attr( - not(any(feature = "fips", feature = "fips-link-precompiled")), - allow(clippy::unnecessary_cast) - )] + #[cfg_attr(not(feature = "fips"), allow(clippy::unnecessary_cast))] { assert!(protocols.len() <= ProtosLen::max_value() as usize); } @@ -2121,9 +2118,9 @@ impl SslContextRef { #[derive(Debug)] pub struct GetSessionPendingError; -#[cfg(not(any(feature = "fips", feature = "fips-link-precompiled")))] +#[cfg(not(feature = "fips"))] type ProtosLen = usize; -#[cfg(any(feature = "fips", feature = "fips-link-precompiled"))] +#[cfg(feature = "fips")] type ProtosLen = libc::c_uint; /// Information about the state of a cipher. @@ -2814,10 +2811,7 @@ impl SslRef { /// [`SSL_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_alpn_protos.html pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { - #[cfg_attr( - not(any(feature = "fips", feature = "fips-link-precompiled")), - allow(clippy::unnecessary_cast) - )] + #[cfg_attr(not(feature = "fips"), allow(clippy::unnecessary_cast))] { assert!(protocols.len() <= ProtosLen::max_value() as usize); } diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index 5140841b..988428f4 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -982,9 +982,9 @@ impl X509NameBuilder { } } -#[cfg(not(any(feature = "fips", feature = "fips-link-precompiled")))] +#[cfg(not(feature = "fips"))] type ValueLen = isize; -#[cfg(any(feature = "fips", feature = "fips-link-precompiled"))] +#[cfg(feature = "fips")] type ValueLen = i32; foreign_type_and_impl_send_sync! { From 5dbf0a57d4ceb60d2c85e39a63fda74aca8d7cdf Mon Sep 17 00:00:00 2001 From: Evan Rittenhouse Date: Mon, 8 Jan 2024 08:43:46 -0600 Subject: [PATCH 10/22] Expose SSL_get_error --- boring/src/ssl/error.rs | 3 +++ boring/src/ssl/mod.rs | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/boring/src/ssl/error.rs b/boring/src/ssl/error.rs index bc792c11..014eb188 100644 --- a/boring/src/ssl/error.rs +++ b/boring/src/ssl/error.rs @@ -13,6 +13,9 @@ use crate::ssl::MidHandshakeSslStream; pub struct ErrorCode(c_int); impl ErrorCode { + /// No error. + pub const NONE: ErrorCode = ErrorCode(ffi::SSL_ERROR_NONE); + /// The SSL session has been closed. pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN); diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 91da2bbd..1524d8e0 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -2635,10 +2635,6 @@ impl SslRef { unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) } } - fn get_error(&self, ret: c_int) -> ErrorCode { - unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) } - } - #[cfg(feature = "kx-safe-default")] fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> { let curves = CString::new(curves).unwrap(); @@ -2683,6 +2679,15 @@ impl SslRef { .expect("invalid default server curves list"); } + /// Returns an `ErrorCode` value for the most recent operation on this `SslRef`. + /// + /// This corresponds to [`SSL_get_error`]. + /// + /// [`SSL_get_error`]: https://github.com/google/boringssl/blob/master/include/openssl/ssl.h#L475 + pub fn error_code(&self, ret: c_int) -> ErrorCode { + unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) } + } + /// Like [`SslContextBuilder::set_verify`]. /// /// This corresponds to [`SSL_set_verify`]. @@ -3762,7 +3767,7 @@ impl SslStream { fn make_error(&mut self, ret: c_int) -> Error { self.check_panic(); - let code = self.ssl.get_error(ret); + let code = self.ssl.error_code(ret); let cause = match code { ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())), From f82f7835516830de3d214f60e8e4c82982534557 Mon Sep 17 00:00:00 2001 From: Reed Loden Date: Mon, 15 Jan 2024 19:00:58 -0800 Subject: [PATCH 11/22] Use Ninja to build BoringSSL Ninja is a required build component, as per the BoringSSL build directions. Using Ninja will also fix this error: > clang-12: error: no such file or directory: 'MAKE_ASM_FLAGS' PR is mostly cribbed from cloudflare/boring#76. --- .github/workflows/ci.yml | 10 ++++++++-- boring-sys/build/main.rs | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98ab144f..f70b3e01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,10 +3,10 @@ name: CI on: pull_request: branches: - - master + - teleport push: branches: - - master + - teleport env: RUSTFLAGS: -Dwarnings @@ -35,6 +35,8 @@ jobs: - name: Get rust version id: rust-version run: echo "::set-output name=version::$(rustc --version)" + - name: Install Ninja + uses: seanmiddleditch/gha-setup-ninja@v4 - name: Cache cargo index uses: actions/cache@v1 with: @@ -244,6 +246,8 @@ jobs: - name: Install Rust (rustup) run: rustup update stable --no-self-update && rustup default stable shell: bash + - name: Install Ninja + uses: seanmiddleditch/gha-setup-ninja@v4 - name: Install Clang-12 uses: KyleMayes/install-llvm-action@v1 with: @@ -305,6 +309,8 @@ jobs: - name: Install Rust (rustup) run: rustup update stable --no-self-update && rustup default stable && rustup target add ${{ matrix.target }} shell: bash + - name: Install Ninja + uses: seanmiddleditch/gha-setup-ninja@v4 - name: Install Clang-12 uses: KyleMayes/install-llvm-action@v1 with: diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index b2ed72f6..b2d9bfaa 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -199,6 +199,10 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { let src_path = get_boringssl_source_path(config); let mut boringssl_cmake = cmake::Config::new(src_path); + if config.features.fips { + boringssl_cmake.generator("Ninja"); + } + if config.host == config.target { return boringssl_cmake; } From 37836c428f520dc1a62a10e2998b9748e8583f0a Mon Sep 17 00:00:00 2001 From: Jonathan Hoyland Date: Tue, 16 Jan 2024 14:49:18 +0000 Subject: [PATCH 12/22] Expose `set_compliance_policy` and `get_ciphers` --- boring/src/ssl/mod.rs | 73 +++++++++++++++++++++++++++++++++++- boring/src/ssl/test/mod.rs | 77 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 2 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 1524d8e0..6b407490 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -89,7 +89,7 @@ use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; use crate::ssl::error::InnerError; -use crate::stack::{Stack, StackRef}; +use crate::stack::{Stack, StackRef, Stackable}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; use crate::x509::verify::X509VerifyParamRef; use crate::x509::{ @@ -701,6 +701,27 @@ impl SslCurve { pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::NID_P256Kyber768Draft00); } +/// A compliance policy. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg(not(feature = "fips"))] +pub struct CompliancePolicy(ffi::ssl_compliance_policy_t); + +#[cfg(not(feature = "fips"))] +impl CompliancePolicy { + /// Does nothing, however setting this does not undo other policies, so trying to set this is an error. + pub const NONE: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_none); + + /// Configures a TLS connection to try and be compliant with NIST requirements, but does not guarantee success. + /// This policy can be called even if Boring is not built with FIPS. + pub const FIPS_202205: Self = + Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_fips_202205); + + /// Partially configures a TLS connection to be compliant with WPA3. Callers must enforce certificate chain requirements themselves. + /// Use of this policy is less secure than the default and not recommended. + pub const WPA3_192_202304: Self = + Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_wpa3_192_202304); +} + /// A standard implementation of protocol selection for Application Layer Protocol Negotiation /// (ALPN). /// @@ -1262,7 +1283,9 @@ impl SslContextBuilder { /// Sets the list of supported ciphers for protocols before TLSv1.3. /// - /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3. + /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3 in OpenSSL. + /// BoringSSL doesn't implement `set_ciphersuites`. + /// See https://github.com/google/boringssl/blob/master/include/openssl/ssl.h#L1542-L1544 /// /// See [`ciphers`] for details on the format. /// @@ -1281,6 +1304,18 @@ impl SslContextBuilder { } } + /// Gets the list of supported ciphers for protocols before TLSv1.3. + /// + /// See [`ciphers`] for details on the format + /// + /// This corresponds to [`SSL_CTX_get_ciphers`]. + /// + /// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html + /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ciphers.html + pub fn ciphers(&self) -> Option<&StackRef> { + self.ctx.ciphers() + } + /// Sets the options used by the context, returning the old set. /// /// This corresponds to [`SSL_CTX_set_options`]. @@ -1856,6 +1891,17 @@ impl SslContextBuilder { } } + /// Sets the context's compliance policy. + /// + /// This corresponds to [`SSL_CTX_set_compliance_policy`] + /// + /// [`SSL_CTX_set_compliance_policy`] https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_compliance_policy + /// This feature isn't available in the certified version of BoringSSL. + #[cfg(not(feature = "fips"))] + pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { + unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.ctx @@ -1936,6 +1982,25 @@ impl SslContext { Index::from_raw(idx) } } + + /// Gets the list of supported ciphers for protocols before TLSv1.3. + /// + /// See [`ciphers`] for details on the format + /// + /// This corresponds to [`SSL_CTX_get_ciphers`]. + /// + /// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html + /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ciphers.html + pub fn ciphers(&self) -> Option<&StackRef> { + unsafe { + let ciphers = ffi::SSL_CTX_get_ciphers(self.as_ptr()); + if ciphers.is_null() { + None + } else { + Some(StackRef::from_ptr(ciphers)) + } + } + } } impl SslContextRef { @@ -2181,6 +2246,10 @@ impl ClientHello<'_> { /// Information about a cipher. pub struct SslCipher(*mut ffi::SSL_CIPHER); +impl Stackable for SslCipher { + type StackType = ffi::stack_st_SSL_CIPHER; +} + unsafe impl ForeignType for SslCipher { type CType = ffi::SSL_CIPHER; type Ref = SslCipherRef; diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 90f203e4..08ef7e28 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -21,6 +21,9 @@ use crate::ssl::{ use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; +#[cfg(not(feature = "fips"))] +use super::CompliancePolicy; + mod custom_verify; mod private_key_method; mod server; @@ -917,6 +920,80 @@ fn server_set_default_curves_list() { ssl.server_set_default_curves_list(); } +#[test] +fn test_get_ciphers() { + let ctx_builder = SslContext::builder(SslMethod::tls()).unwrap(); + let ctx_builder_ciphers: Vec<&str> = ctx_builder + .ciphers() + .unwrap() + .into_iter() + .map(|v| v.name()) + .collect(); + assert!(!(ctx_builder_ciphers.is_empty())); + + let ctx = ctx_builder.build(); + let ctx_ciphers: Vec<&str> = ctx + .ciphers() + .unwrap() + .into_iter() + .map(|v| v.name()) + .collect(); + assert!(!(ctx_ciphers.is_empty())); + + assert_eq!(ctx_builder_ciphers.len(), ctx_ciphers.len()); + + for (ctx_builder_cipher, ctx_cipher) in ctx_builder_ciphers.into_iter().zip(ctx_ciphers) { + assert_eq!(ctx_builder_cipher, ctx_cipher); + } +} + +#[test] +#[cfg(not(feature = "fips"))] +fn test_set_compliance() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) + .unwrap(); + + assert_eq!(ctx.max_proto_version().unwrap(), SslVersion::TLS1_3); + assert_eq!(ctx.min_proto_version().unwrap(), SslVersion::TLS1_2); + + const FIPS_CIPHERS: [&str; 4] = [ + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + ]; + + let ciphers = ctx.ciphers().unwrap(); + assert_eq!(ciphers.len(), FIPS_CIPHERS.len()); + + for cipher in ciphers.into_iter().zip(FIPS_CIPHERS) { + assert_eq!(cipher.0.name(), cipher.1) + } + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_compliance_policy(CompliancePolicy::WPA3_192_202304) + .unwrap(); + + assert_eq!(ctx.max_proto_version().unwrap(), SslVersion::TLS1_3); + assert_eq!(ctx.min_proto_version().unwrap(), SslVersion::TLS1_2); + + const WPA3_192_CIPHERS: [&str; 2] = [ + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + ]; + + let ciphers = ctx.ciphers().unwrap(); + assert_eq!(ciphers.len(), WPA3_192_CIPHERS.len()); + + for cipher in ciphers.into_iter().zip(WPA3_192_CIPHERS) { + assert_eq!(cipher.0.name(), cipher.1) + } + + ctx.set_compliance_policy(CompliancePolicy::NONE) + .expect_err("Testing expect err if set compliance policy to NONE"); +} + #[test] fn drop_ex_data_in_context() { let index = SslContext::new_ex_index::<&'static str>().unwrap(); From 2c708570d1d4f8bb8230d06402582258ffa80eca Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 17 Jan 2024 17:58:57 +0100 Subject: [PATCH 13/22] Release 4.4.0 --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5c6ff949..94b6f08c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "4.3.0" +version = "4.4.0" repository = "https://github.com/cloudflare/boring" edition = "2021" @@ -19,9 +19,9 @@ tag-prefix = "" publish = false [workspace.dependencies] -boring-sys = { version = "4.3.0", path = "./boring-sys" } -boring = { version = "4.3.0", path = "./boring" } -tokio-boring = { version = "4.3.0", path = "./tokio-boring" } +boring-sys = { version = "4.4.0", path = "./boring-sys" } +boring = { version = "4.4.0", path = "./boring" } +tokio-boring = { version = "4.4.0", path = "./tokio-boring" } bindgen = { version = "0.68.1", default-features = false, features = ["runtime"] } cmake = "0.1.18" From 04af91212e4502852c9dd2ec8aff29535a859bef Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Mon, 1 Jan 2024 22:35:42 -0800 Subject: [PATCH 14/22] Updates boringssl-fips to fips-20220613 --- boring-sys/deps/boringssl-fips | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boring-sys/deps/boringssl-fips b/boring-sys/deps/boringssl-fips index 853ca1ea..0c6f4013 160000 --- a/boring-sys/deps/boringssl-fips +++ b/boring-sys/deps/boringssl-fips @@ -1 +1 @@ -Subproject commit 853ca1ea1168dff08011e5d42d94609cc0ca2e27 +Subproject commit 0c6f40132b828e92ba365c6b7680e32820c63fa7 From 5e4c9a6e69d90679d172d50acfcb5a83be61ba41 Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Tue, 2 Jan 2024 09:56:24 -0800 Subject: [PATCH 15/22] Updates required clang version to 14.0.0 --- .github/workflows/ci.yml | 16 ++++++++-------- boring-sys/build/main.rs | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7eb8dec6..ad6bf382 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -248,14 +248,14 @@ jobs: shell: bash - name: Install Ninja uses: seanmiddleditch/gha-setup-ninja@v4 - - name: Install Clang-12 + - name: Install Clang-14 uses: KyleMayes/install-llvm-action@v1 with: - version: "12.0.0" + version: "14.0.0" directory: ${{ runner.temp }}/llvm - - name: Add clang++-12 link + - name: Add clang++-14 link working-directory: ${{ runner.temp }}/llvm/bin - run: ln -s clang clang++-12 + run: ln -s clang clang++-14 - name: Run tests run: cargo test --features fips - name: Test boring-sys cargo publish (FIPS) @@ -311,14 +311,14 @@ jobs: shell: bash - name: Install Ninja uses: seanmiddleditch/gha-setup-ninja@v4 - - name: Install Clang-12 + - name: Install Clang-14 uses: KyleMayes/install-llvm-action@v1 with: - version: "12.0.0" + version: "14.0.0" directory: ${{ runner.temp }}/llvm - - name: Add clang++-12 link + - name: Add clang++-14 link working-directory: ${{ runner.temp }}/llvm/bin - run: ln -s clang clang++-12 + run: ln -s clang clang++-14 - name: Install ${{ matrix.target }} toolchain run: brew tap messense/macos-cross-toolchains && brew install ${{ matrix.target }} - name: Set BORING_BSSL_FIPS_COMPILER_EXTERNAL_TOOLCHAIN diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 712b71ad..bf88f958 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -354,9 +354,9 @@ fn verify_fips_clang_version() -> (&'static str, &'static str) { Some(output.lines().next().expect("empty output").to_string()) } - const REQUIRED_CLANG_VERSION: &str = "12.0.0"; + const REQUIRED_CLANG_VERSION: &str = "14.0.0"; for (cc, cxx) in [ - ("clang-12", "clang++-12"), + ("clang-14", "clang++-14"), ("clang", "clang++"), ("cc", "c++"), ] { From 199bebde3c26584023fde0b0afbcb1f2c74a9910 Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Tue, 2 Jan 2024 21:30:55 -0800 Subject: [PATCH 16/22] updates to 14.0.6 --- .github/workflows/ci.yml | 4 ++-- boring-sys/build/main.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad6bf382..b0844121 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -251,7 +251,7 @@ jobs: - name: Install Clang-14 uses: KyleMayes/install-llvm-action@v1 with: - version: "14.0.0" + version: "14.0.6" directory: ${{ runner.temp }}/llvm - name: Add clang++-14 link working-directory: ${{ runner.temp }}/llvm/bin @@ -314,7 +314,7 @@ jobs: - name: Install Clang-14 uses: KyleMayes/install-llvm-action@v1 with: - version: "14.0.0" + version: "14.0.6" directory: ${{ runner.temp }}/llvm - name: Add clang++-14 link working-directory: ${{ runner.temp }}/llvm/bin diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index bf88f958..1a025c72 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -354,7 +354,7 @@ fn verify_fips_clang_version() -> (&'static str, &'static str) { Some(output.lines().next().expect("empty output").to_string()) } - const REQUIRED_CLANG_VERSION: &str = "14.0.0"; + const REQUIRED_CLANG_VERSION: &str = "14.0.6"; for (cc, cxx) in [ ("clang-14", "clang++-14"), ("clang", "clang++"), From 79a2bc693d51e46662a7fd21947bf198ed29bc8f Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Wed, 10 Jan 2024 11:02:05 -0800 Subject: [PATCH 17/22] force cmake generator to Ninja --- boring-sys/build/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 1a025c72..4753ee22 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -198,6 +198,7 @@ fn get_boringssl_platform_output_path(config: &Config) -> String { fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { let src_path = get_boringssl_source_path(config); let mut boringssl_cmake = cmake::Config::new(src_path); + boringssl_cmake.generator("Ninja"); if config.features.fips { boringssl_cmake.generator("Ninja"); From 402c1164efe75d0a960af9740ff5cf4a1aea4f51 Mon Sep 17 00:00:00 2001 From: Reed Loden Date: Sun, 21 Jan 2024 20:13:13 -0800 Subject: [PATCH 18/22] Require Clang 14.0.x, install Ninja, only require Ninja for FIPS * BoringCrypto just installs the latest Clang 14.0.x release, so match * Install Ninja for CI to pass * Only require Ninja for FIPS builds (FIPS build requires Ninja) * Bump actions/* versions to address EOL warnings Should consider requiring Ninja for all builds, as per #76, as upstream recommends it. --- .github/workflows/ci.yml | 24 ++++++++++++------------ boring-sys/build/main.rs | 7 +++++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0844121..8f34f1de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: name: rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Rust run: rustup update stable && rustup default stable - name: Check formatting @@ -27,7 +27,7 @@ jobs: name: clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - name: Install Rust @@ -38,7 +38,7 @@ jobs: - name: Install Ninja uses: seanmiddleditch/gha-setup-ninja@v4 - name: Cache cargo index - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} @@ -47,14 +47,14 @@ jobs: - name: Create lockfile run: cargo generate-lockfile - name: Cache cargo registry - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - name: Fetch dependencies run: cargo fetch - name: Cache target directory - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: target key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} @@ -186,7 +186,7 @@ jobs: extra_test_args: --workspace --exclude tokio-boring --exclude hyper-boring steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - name: Install Rust (rustup) @@ -240,7 +240,7 @@ jobs: name: Test FIPS integration runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - name: Install Rust (rustup) @@ -251,7 +251,7 @@ jobs: - name: Install Clang-14 uses: KyleMayes/install-llvm-action@v1 with: - version: "14.0.6" + version: "14.0" directory: ${{ runner.temp }}/llvm - name: Add clang++-14 link working-directory: ${{ runner.temp }}/llvm/bin @@ -279,7 +279,7 @@ jobs: include: - target: x86_64-unknown-linux-gnu steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - name: Install Rust (rustup) @@ -303,7 +303,7 @@ jobs: include: - target: x86_64-unknown-linux-gnu steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - name: Install Rust (rustup) @@ -314,7 +314,7 @@ jobs: - name: Install Clang-14 uses: KyleMayes/install-llvm-action@v1 with: - version: "14.0.6" + version: "14.0" directory: ${{ runner.temp }}/llvm - name: Add clang++-14 link working-directory: ${{ runner.temp }}/llvm/bin @@ -336,7 +336,7 @@ jobs: name: Test features runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - name: Install Rust (rustup) diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 4753ee22..d87e25bb 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -198,7 +198,10 @@ fn get_boringssl_platform_output_path(config: &Config) -> String { fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { let src_path = get_boringssl_source_path(config); let mut boringssl_cmake = cmake::Config::new(src_path); - boringssl_cmake.generator("Ninja"); + + if config.features.fips { + boringssl_cmake.generator("Ninja"); + } if config.features.fips { boringssl_cmake.generator("Ninja"); @@ -355,7 +358,7 @@ fn verify_fips_clang_version() -> (&'static str, &'static str) { Some(output.lines().next().expect("empty output").to_string()) } - const REQUIRED_CLANG_VERSION: &str = "14.0.6"; + const REQUIRED_CLANG_VERSION: &str = "14.0"; for (cc, cxx) in [ ("clang-14", "clang++-14"), ("clang", "clang++"), From 28b12c1154224edeea1f245211dd55f4eabde208 Mon Sep 17 00:00:00 2001 From: Reed Loden Date: Sun, 21 Jan 2024 20:51:35 -0800 Subject: [PATCH 19/22] Enable compliance policy when in FIPS mode --- boring-sys/build.rs | 1 + boring/src/fips.rs | 4 ++-- boring/src/lib.rs | 4 ++-- boring/src/ssl/mod.rs | 7 +++---- boring/src/ssl/test/mod.rs | 2 -- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/boring-sys/build.rs b/boring-sys/build.rs index e71886d5..e50c84fd 100644 --- a/boring-sys/build.rs +++ b/boring-sys/build.rs @@ -308,6 +308,7 @@ fn get_boringssl_cmake_config() -> cmake::Config { /// 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: update above URL once BoringCrypto CMVP certification for `fips-20220613` is approved // 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 { diff --git a/boring/src/fips.rs b/boring/src/fips.rs index e578ae75..c02ff597 100644 --- a/boring/src/fips.rs +++ b/boring/src/fips.rs @@ -1,11 +1,11 @@ -//! FIPS 140-2 support. +//! FIPS 140-3 support. //! //! See [OpenSSL's documentation] for details. //! //! [OpenSSL's documentation]: https://www.openssl.org/docs/fips/UserGuide-2.0.pdf use crate::ffi; -/// Determines if the library is running in the FIPS 140-2 mode of operation. +/// Determines if the library is running in the FIPS 140-3 mode of operation. /// /// This corresponds to `FIPS_mode`. pub fn enabled() -> bool { diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 27c1ebcd..149eac71 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -41,8 +41,8 @@ //! //! ## 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) +//! Only BoringCrypto module version `0c6f40132b828e92ba365c6b7680e32820c63fa7`, as certified with +//! [FIPS 140-3 certificate XXX](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/XXX) //! 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: diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 6b407490..eb92da27 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -703,10 +703,8 @@ impl SslCurve { /// A compliance policy. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg(not(feature = "fips"))] pub struct CompliancePolicy(ffi::ssl_compliance_policy_t); -#[cfg(not(feature = "fips"))] impl CompliancePolicy { /// Does nothing, however setting this does not undo other policies, so trying to set this is an error. pub const NONE: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_none); @@ -826,6 +824,9 @@ impl SslContextBuilder { init(); let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?; + #[cfg(feature = "fips")] + ctx.set_compliance_policy(CompliancePolicy::FIPS_202205).unwrap(); + #[cfg(feature = "rpk")] { Ok(SslContextBuilder::from_ptr(ctx, false)) @@ -1896,8 +1897,6 @@ impl SslContextBuilder { /// This corresponds to [`SSL_CTX_set_compliance_policy`] /// /// [`SSL_CTX_set_compliance_policy`] https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_compliance_policy - /// This feature isn't available in the certified version of BoringSSL. - #[cfg(not(feature = "fips"))] pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } } diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 08ef7e28..77feda45 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -21,7 +21,6 @@ use crate::ssl::{ use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; -#[cfg(not(feature = "fips"))] use super::CompliancePolicy; mod custom_verify; @@ -948,7 +947,6 @@ fn test_get_ciphers() { } #[test] -#[cfg(not(feature = "fips"))] fn test_set_compliance() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) From 048c8ec0de01ab2a54a34201d787ba274d908b92 Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Tue, 23 Jan 2024 12:24:19 -0800 Subject: [PATCH 20/22] removes duplicate Ninja setting, comply with formatting --- boring-sys/build/main.rs | 4 ---- boring/src/ssl/mod.rs | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index d87e25bb..46ee2d0d 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -203,10 +203,6 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { boringssl_cmake.generator("Ninja"); } - if config.features.fips { - boringssl_cmake.generator("Ninja"); - } - if config.host == config.target { return boringssl_cmake; } diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index eb92da27..96cee8c7 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -825,7 +825,8 @@ impl SslContextBuilder { let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?; #[cfg(feature = "fips")] - ctx.set_compliance_policy(CompliancePolicy::FIPS_202205).unwrap(); + ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) + .unwrap(); #[cfg(feature = "rpk")] { From 69d40839ccbc381efa1a4465d42de0f49a2cd0a4 Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Wed, 24 Jan 2024 10:29:10 -0800 Subject: [PATCH 21/22] Gate compliance policy apis: The SSL_CTX_set_compliance_policy and ssl_compliance_policy_t apis are not available in the fips validated hash of the boringssl library (boring-sys/deps/boringssl-fips). This adds back the feature gate for these apis. --- boring/src/ssl/mod.rs | 8 ++++---- boring/src/ssl/test/mod.rs | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 96cee8c7..6b407490 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -703,8 +703,10 @@ impl SslCurve { /// A compliance policy. #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg(not(feature = "fips"))] pub struct CompliancePolicy(ffi::ssl_compliance_policy_t); +#[cfg(not(feature = "fips"))] impl CompliancePolicy { /// Does nothing, however setting this does not undo other policies, so trying to set this is an error. pub const NONE: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_none); @@ -824,10 +826,6 @@ impl SslContextBuilder { init(); let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?; - #[cfg(feature = "fips")] - ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) - .unwrap(); - #[cfg(feature = "rpk")] { Ok(SslContextBuilder::from_ptr(ctx, false)) @@ -1898,6 +1896,8 @@ impl SslContextBuilder { /// This corresponds to [`SSL_CTX_set_compliance_policy`] /// /// [`SSL_CTX_set_compliance_policy`] https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_compliance_policy + /// This feature isn't available in the certified version of BoringSSL. + #[cfg(not(feature = "fips"))] pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } } diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 77feda45..08ef7e28 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -21,6 +21,7 @@ use crate::ssl::{ use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; +#[cfg(not(feature = "fips"))] use super::CompliancePolicy; mod custom_verify; @@ -947,6 +948,7 @@ fn test_get_ciphers() { } #[test] +#[cfg(not(feature = "fips"))] fn test_set_compliance() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) From 83055ff0dcf6f88f58a642902b53d2592d74382e Mon Sep 17 00:00:00 2001 From: Isaiah Becker-Mayer Date: Wed, 24 Jan 2024 11:43:18 -0800 Subject: [PATCH 22/22] Adds BORING_BSSL_CPLUS_INCLUDE_PATH env variable handling --- boring-sys/build/config.rs | 2 ++ boring-sys/build/main.rs | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index d05396ae..ae4c32b3 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -24,6 +24,7 @@ pub(crate) struct Features { pub(crate) struct Env { pub(crate) path: Option, pub(crate) include_path: Option, + pub(crate) cplus_include_path: Option, pub(crate) source_path: Option, pub(crate) precompiled_bcm_o: Option, pub(crate) assume_patched: bool, @@ -146,6 +147,7 @@ impl Env { Self { path: boringssl_var("BORING_BSSL_PATH").map(PathBuf::from), include_path: boringssl_var("BORING_BSSL_INCLUDE_PATH").map(PathBuf::from), + cplus_include_path: boringssl_var("BORING_BSSL_CPLUS_INCLUDE_PATH").map(PathBuf::from), source_path: boringssl_var("BORING_BSSL_SOURCE_PATH").map(PathBuf::from), precompiled_bcm_o: boringssl_var("BORING_BSSL_PRECOMPILED_BCM_O").map(PathBuf::from), assume_patched: boringssl_var("BORING_BSSL_ASSUME_PATCHED") diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 46ee2d0d..23ca28a0 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -619,8 +619,17 @@ fn link_in_precompiled_bcm_o(config: &Config) { .unwrap(); } +// Note: this is the entrypoint into the boring-sys build process. fn main() { let config = Config::from_env(); + + if let Some(ref cplus_include_path) = config.env.cplus_include_path { + // Inject CPLUS_INCLUDE_PATH into the environment for the build. + // This must be done before we build the boring source path so that it can + // be used during that build process. + std::env::set_var("CPLUS_INCLUDE_PATH", cplus_include_path); + } + let bssl_dir = built_boring_source_path(&config); let build_path = get_boringssl_platform_output_path(&config);