Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
231010c0cb
|
|
@ -25,8 +25,8 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Rust
|
- name: Install Rustfmt
|
||||||
run: rustup update stable && rustup default stable
|
run: rustup default stable && rustup component add rustfmt
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
|
|
||||||
|
|
@ -38,10 +38,11 @@ jobs:
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
run: rustup update stable && rustup default stable
|
run: rustup update --no-self-update stable && rustup default stable && rustup component add clippy
|
||||||
- name: Get rust version
|
- name: Get rust version
|
||||||
id: rust-version
|
id: rust-version
|
||||||
run: echo "::set-output name=version::$(rustc --version)"
|
run: |
|
||||||
|
echo "version=$(rustc --version)" >> $GITHUB_OUTPUT
|
||||||
- name: Cache cargo index
|
- name: Cache cargo index
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -157,8 +158,8 @@ jobs:
|
||||||
apt_packages: gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
|
apt_packages: gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
|
||||||
check_only: true
|
check_only: true
|
||||||
custom_env:
|
custom_env:
|
||||||
CC: arm-linux-gnueabi-gcc
|
CC_arm-unknown-linux-gnueabi: arm-linux-gnueabi-gcc
|
||||||
CXX: arm-linux-gnueabi-g++
|
CXX_arm-unknown-linux-gnueabi: arm-linux-gnueabi-g++
|
||||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER: arm-linux-gnueabi-g++
|
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER: arm-linux-gnueabi-g++
|
||||||
extra_test_args: --workspace --exclude compio-boring2
|
extra_test_args: --workspace --exclude compio-boring2
|
||||||
- thing: aarch64-linux
|
- thing: aarch64-linux
|
||||||
|
|
@ -168,8 +169,8 @@ jobs:
|
||||||
apt_packages: crossbuild-essential-arm64
|
apt_packages: crossbuild-essential-arm64
|
||||||
check_only: true
|
check_only: true
|
||||||
custom_env:
|
custom_env:
|
||||||
CC: aarch64-linux-gnu-gcc
|
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
|
||||||
CXX: aarch64-linux-gnu-g++
|
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
|
||||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-g++
|
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-g++
|
||||||
- thing: arm64-macos
|
- thing: arm64-macos
|
||||||
target: aarch64-apple-darwin
|
target: aarch64-apple-darwin
|
||||||
|
|
@ -214,6 +215,10 @@ jobs:
|
||||||
# run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
|
# run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
|
||||||
# shell: bash
|
# shell: bash
|
||||||
- run: rustup target add ${{ matrix.target }}
|
- run: rustup target add ${{ matrix.target }}
|
||||||
|
- name: Install golang
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '>=1.22.0'
|
||||||
- name: Install target-specific APT dependencies
|
- name: Install target-specific APT dependencies
|
||||||
if: "matrix.apt_packages != ''"
|
if: "matrix.apt_packages != ''"
|
||||||
run: sudo apt update && sudo apt install -y ${{ matrix.apt_packages }}
|
run: sudo apt update && sudo apt install -y ${{ matrix.apt_packages }}
|
||||||
|
|
@ -272,6 +277,10 @@ jobs:
|
||||||
- name: Install Rust (rustup)
|
- name: Install Rust (rustup)
|
||||||
run: rustup update stable --no-self-update && rustup default stable && rustup target add ${{ matrix.target }}
|
run: rustup update stable --no-self-update && rustup default stable && rustup target add ${{ matrix.target }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
- name: Install golang
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '>=1.22.0'
|
||||||
- name: Install ${{ matrix.target }} toolchain
|
- name: Install ${{ matrix.target }} toolchain
|
||||||
run: brew tap messense/macos-cross-toolchains && brew install ${{ matrix.target }}
|
run: brew tap messense/macos-cross-toolchains && brew install ${{ matrix.target }}
|
||||||
- name: Set BORING_BSSL_SYSROOT
|
- name: Set BORING_BSSL_SYSROOT
|
||||||
|
|
@ -291,14 +300,10 @@ jobs:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: Install Rust (rustup)
|
- name: Install Rust (rustup)
|
||||||
run: rustup update stable --no-self-update && rustup default stable
|
run: rustup update stable --no-self-update && rustup default stable
|
||||||
- run: cargo test --features pq-experimental
|
- name: Run `kx-safe-default` tests
|
||||||
name: Run `pq-experimental` tests
|
run: cargo test --features kx-safe-default
|
||||||
- run: cargo test --features kx-safe-default,pq-experimental
|
- name: Run `underscore-wildcards` tests
|
||||||
name: Run `kx-safe-default` tests
|
run: cargo test --features underscore-wildcards
|
||||||
- run: cargo test --features pq-experimental,underscore-wildcards
|
|
||||||
name: Run `pq-experimental,underscore-wildcards` tests
|
|
||||||
- run: cargo test --features underscore-wildcards
|
|
||||||
name: Run `underscore-wildcards` tests
|
|
||||||
|
|
||||||
crates:
|
crates:
|
||||||
name: crates
|
name: crates
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,3 @@
|
||||||
path = boring-sys/deps/boringssl
|
path = boring-sys/deps/boringssl
|
||||||
url = https://github.com/google/boringssl.git
|
url = https://github.com/google/boringssl.git
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
[submodule "boring-sys/deps/boringssl-fips"]
|
|
||||||
path = boring-sys/deps/boringssl-fips
|
|
||||||
url = https://github.com/google/boringssl.git
|
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,12 @@ tokio-boring = { package = "tokio-boring2", version = "5.0.0-alpha.10", path = "
|
||||||
compio-boring = { package = "compio-boring2", version = "5.0.0-alpha.10", path = "./compio-boring" }
|
compio-boring = { package = "compio-boring2", version = "5.0.0-alpha.10", path = "./compio-boring" }
|
||||||
|
|
||||||
bindgen = { version = "0.72.0", default-features = false, features = ["runtime"] }
|
bindgen = { version = "0.72.0", default-features = false, features = ["runtime"] }
|
||||||
|
bitflags = "2.9"
|
||||||
|
brotli = "8.0"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
cmake = "0.1.18"
|
cmake = "0.1.54"
|
||||||
fs_extra = "1.3.0"
|
fs_extra = "1.3.0"
|
||||||
fslock = "0.2"
|
fslock = "0.2"
|
||||||
bitflags = "2.4"
|
|
||||||
foreign-types = "0.5"
|
foreign-types = "0.5"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|
@ -42,6 +43,5 @@ antidote = "1.0.0"
|
||||||
linked_hash_set = "0.1"
|
linked_hash_set = "0.1"
|
||||||
openssl-macros = "0.1.1"
|
openssl-macros = "0.1.1"
|
||||||
autocfg = "1.3.0"
|
autocfg = "1.3.0"
|
||||||
brotli = "8"
|
|
||||||
compio = { version = "0.16.0" }
|
compio = { version = "0.16.0" }
|
||||||
compio-io = { version = "0.8.0" }
|
compio-io = { version = "0.8.0" }
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,12 @@ build = "build/main.rs"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
categories = ["cryptography", "external-ffi-bindings"]
|
categories = ["cryptography", "external-ffi-bindings"]
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
|
rust-version = "1.77"
|
||||||
include = [
|
include = [
|
||||||
"/*.md",
|
"/*.md",
|
||||||
"/*.toml",
|
"/*.toml",
|
||||||
"/LICENSE-MIT",
|
"/LICENSE-MIT",
|
||||||
"/cmake/*.cmake",
|
"/cmake/*.cmake",
|
||||||
# boringssl (non-FIPS)
|
|
||||||
"/deps/boringssl/src/util/32-bit-toolchain.cmake",
|
|
||||||
"/deps/boringssl/**/*.[chS]",
|
"/deps/boringssl/**/*.[chS]",
|
||||||
"/deps/boringssl/**/*.asm",
|
"/deps/boringssl/**/*.asm",
|
||||||
"/deps/boringssl/sources.json",
|
"/deps/boringssl/sources.json",
|
||||||
|
|
@ -27,34 +26,18 @@ include = [
|
||||||
"/deps/boringssl/src/crypto/obj/objects.txt",
|
"/deps/boringssl/src/crypto/obj/objects.txt",
|
||||||
"/deps/boringssl/src/util/32-bit-toolchain.cmake",
|
"/deps/boringssl/src/util/32-bit-toolchain.cmake",
|
||||||
"/deps/boringssl/**/*.bzl",
|
"/deps/boringssl/**/*.bzl",
|
||||||
"/deps/boringssl/src/**/*.cc",
|
"/deps/boringssl/**/*.cc",
|
||||||
"/deps/boringssl/**/CMakeLists.txt",
|
"/deps/boringssl/**/CMakeLists.txt",
|
||||||
"/deps/boringssl/**/sources.cmake",
|
"/deps/boringssl/**/sources.cmake",
|
||||||
|
"/deps/boringssl/**/util/go_tests.txt",
|
||||||
"/deps/boringssl/LICENSE",
|
"/deps/boringssl/LICENSE",
|
||||||
# boringssl (FIPS)
|
|
||||||
"/deps/boringssl-fips/src/util/32-bit-toolchain.cmake",
|
|
||||||
"/deps/boringssl-fips/**/*.[chS]",
|
|
||||||
"/deps/boringssl-fips/**/*.asm",
|
|
||||||
"/deps/boringssl-fips/**/*.pl",
|
|
||||||
"/deps/boringssl-fips/**/*.go",
|
|
||||||
"/deps/boringssl-fips/**/go.mod",
|
|
||||||
"/deps/boringssl-fips/**/go.sum",
|
|
||||||
"/deps/boringssl-fips/sources.json",
|
|
||||||
"/deps/boringssl-fips/crypto/obj/obj_mac.num",
|
|
||||||
"/deps/boringssl-fips/crypto/obj/objects.txt",
|
|
||||||
"/deps/boringssl-fips/crypto/err/*.errordata",
|
|
||||||
"/deps/boringssl-fips/**/*.bzl",
|
|
||||||
"/deps/boringssl-fips/**/*.cc",
|
|
||||||
"/deps/boringssl-fips/**/CMakeLists.txt",
|
|
||||||
"/deps/boringssl-fips/**/sources.cmake",
|
|
||||||
"/deps/boringssl-fips/LICENSE",
|
|
||||||
"/build/*",
|
"/build/*",
|
||||||
"/src",
|
"/src",
|
||||||
"/patches",
|
"/patches",
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["pq-experimental", "underscore-wildcards"]
|
features = ["underscore-wildcards"]
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
@ -66,28 +49,15 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
# for instructions and more details on the boringssl FIPS flag.
|
# for instructions and more details on the boringssl FIPS flag.
|
||||||
fips = []
|
fips = []
|
||||||
|
|
||||||
# Use a precompiled FIPS-validated version of BoringSSL. Meant to be used with
|
|
||||||
# FIPS-20230428 or newer. Users must set `BORING_BSSL_FIPS_PATH` to use this
|
|
||||||
# feature, or else the build will fail.
|
|
||||||
fips-precompiled = []
|
|
||||||
|
|
||||||
# Link with precompiled FIPS-validated `bcm.o` module.
|
|
||||||
fips-link-precompiled = []
|
|
||||||
|
|
||||||
# Applies a patch (`patches/boring-pq.patch`) to the boringSSL source code that
|
|
||||||
# enables support for PQ key exchange. This feature is necessary in order to
|
|
||||||
# compile the bindings for the default branch of boringSSL (`deps/boringssl`).
|
|
||||||
# Alternatively, a version of boringSSL that implements the same feature set
|
|
||||||
# can be provided by setting `BORING_BSSL{,_FIPS}_SOURCE_PATH`.
|
|
||||||
pq-experimental = []
|
|
||||||
|
|
||||||
# Applies a patch (`patches/underscore-wildcards.patch`) to enable
|
# Applies a patch (`patches/underscore-wildcards.patch`) to enable
|
||||||
# `ffi::X509_CHECK_FLAG_UNDERSCORE_WILDCARDS`. Same caveats as
|
# `ffi::X509_CHECK_FLAG_UNDERSCORE_WILDCARDS`. This feature is necessary in
|
||||||
# those for `pq-experimental` feature apply.
|
# order to compile the bindings for the default branch of boringSSL
|
||||||
|
# (`deps/boringssl`). Alternatively, a version of boringSSL that implements the
|
||||||
|
# same feature set can be provided by setting
|
||||||
|
# `BORING_BSSL{,_FIPS}_SOURCE_PATH`.
|
||||||
underscore-wildcards = []
|
underscore-wildcards = []
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
autocfg = { workspace = true }
|
|
||||||
bindgen = { workspace = true }
|
bindgen = { workspace = true }
|
||||||
cmake = { workspace = true }
|
cmake = { workspace = true }
|
||||||
fs_extra = { workspace = true }
|
fs_extra = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,6 @@ pub(crate) struct Config {
|
||||||
|
|
||||||
pub(crate) struct Features {
|
pub(crate) struct Features {
|
||||||
pub(crate) fips: bool,
|
pub(crate) fips: bool,
|
||||||
pub(crate) fips_precompiled: bool,
|
|
||||||
pub(crate) fips_link_precompiled: bool,
|
|
||||||
pub(crate) pq_experimental: bool,
|
|
||||||
pub(crate) rpk: bool,
|
pub(crate) rpk: bool,
|
||||||
pub(crate) underscore_wildcards: bool,
|
pub(crate) underscore_wildcards: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +24,6 @@ pub(crate) struct Env {
|
||||||
pub(crate) path: Option<PathBuf>,
|
pub(crate) path: Option<PathBuf>,
|
||||||
pub(crate) include_path: Option<PathBuf>,
|
pub(crate) include_path: Option<PathBuf>,
|
||||||
pub(crate) source_path: Option<PathBuf>,
|
pub(crate) source_path: Option<PathBuf>,
|
||||||
pub(crate) precompiled_bcm_o: Option<PathBuf>,
|
|
||||||
pub(crate) assume_patched: bool,
|
pub(crate) assume_patched: bool,
|
||||||
pub(crate) sysroot: Option<PathBuf>,
|
pub(crate) sysroot: Option<PathBuf>,
|
||||||
pub(crate) compiler_external_toolchain: Option<PathBuf>,
|
pub(crate) compiler_external_toolchain: Option<PathBuf>,
|
||||||
|
|
@ -36,6 +32,9 @@ pub(crate) struct Env {
|
||||||
pub(crate) android_ndk_home: Option<PathBuf>,
|
pub(crate) android_ndk_home: Option<PathBuf>,
|
||||||
pub(crate) cmake_toolchain_file: Option<PathBuf>,
|
pub(crate) cmake_toolchain_file: Option<PathBuf>,
|
||||||
pub(crate) cpp_runtime_lib: Option<OsString>,
|
pub(crate) cpp_runtime_lib: Option<OsString>,
|
||||||
|
/// C compiler (ignored if using FIPS)
|
||||||
|
pub(crate) cc: Option<OsString>,
|
||||||
|
pub(crate) cxx: Option<OsString>,
|
||||||
pub(crate) docs_rs: bool,
|
pub(crate) docs_rs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,10 +50,10 @@ impl Config {
|
||||||
let features = Features::from_env();
|
let features = Features::from_env();
|
||||||
let env = Env::from_env(&host, &target, features.is_fips_like());
|
let env = Env::from_env(&host, &target, features.is_fips_like());
|
||||||
|
|
||||||
let mut is_bazel = false;
|
let is_bazel = env
|
||||||
if let Some(src_path) = &env.source_path {
|
.source_path
|
||||||
is_bazel = src_path.join("src").exists();
|
.as_ref()
|
||||||
}
|
.is_some_and(|path| path.join("src").exists());
|
||||||
|
|
||||||
let config = Self {
|
let config = Self {
|
||||||
manifest_dir,
|
manifest_dir,
|
||||||
|
|
@ -78,10 +77,6 @@ impl Config {
|
||||||
panic!("`fips` and `rpk` features are mutually exclusive");
|
panic!("`fips` and `rpk` features are mutually exclusive");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.features.fips_precompiled && self.features.rpk {
|
|
||||||
panic!("`fips-precompiled` and `rpk` features are mutually exclusive");
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_precompiled_native_lib = self.env.path.is_some();
|
let is_precompiled_native_lib = self.env.path.is_some();
|
||||||
let is_external_native_lib_source =
|
let is_external_native_lib_source =
|
||||||
!is_precompiled_native_lib && self.env.source_path.is_none();
|
!is_precompiled_native_lib && self.env.source_path.is_none();
|
||||||
|
|
@ -93,9 +88,7 @@ impl Config {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let features_with_patches_enabled = self.features.rpk
|
let features_with_patches_enabled = self.features.rpk || self.features.underscore_wildcards;
|
||||||
|| self.features.pq_experimental
|
|
||||||
|| self.features.underscore_wildcards;
|
|
||||||
|
|
||||||
let patches_required = features_with_patches_enabled && !self.env.assume_patched;
|
let patches_required = features_with_patches_enabled && !self.env.assume_patched;
|
||||||
|
|
||||||
|
|
@ -104,60 +97,41 @@ impl Config {
|
||||||
"cargo:warning=precompiled BoringSSL was provided, so patches will be ignored"
|
"cargo:warning=precompiled BoringSSL was provided, so patches will be ignored"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(rmehra): should this even be a restriction? why not let people link a custom bcm.o?
|
|
||||||
// precompiled boringssl will include libcrypto.a
|
|
||||||
if is_precompiled_native_lib && self.features.fips_link_precompiled {
|
|
||||||
panic!("precompiled BoringSSL was provided, so FIPS configuration can't be applied");
|
|
||||||
}
|
|
||||||
|
|
||||||
if !is_precompiled_native_lib && self.features.fips_precompiled {
|
|
||||||
panic!("`fips-precompiled` feature requires `BORING_BSSL_FIPS_PATH` to be set");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Features {
|
impl Features {
|
||||||
fn from_env() -> Self {
|
fn from_env() -> Self {
|
||||||
let fips = env::var_os("CARGO_FEATURE_FIPS").is_some();
|
let fips = env::var_os("CARGO_FEATURE_FIPS").is_some();
|
||||||
let fips_precompiled = env::var_os("CARGO_FEATURE_FIPS_PRECOMPILED").is_some();
|
|
||||||
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 rpk = env::var_os("CARGO_FEATURE_RPK").is_some();
|
||||||
let underscore_wildcards = env::var_os("CARGO_FEATURE_UNDERSCORE_WILDCARDS").is_some();
|
let underscore_wildcards = env::var_os("CARGO_FEATURE_UNDERSCORE_WILDCARDS").is_some();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
fips,
|
fips,
|
||||||
fips_precompiled,
|
|
||||||
fips_link_precompiled,
|
|
||||||
pq_experimental,
|
|
||||||
rpk,
|
rpk,
|
||||||
underscore_wildcards,
|
underscore_wildcards,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_fips_like(&self) -> bool {
|
pub(crate) fn is_fips_like(&self) -> bool {
|
||||||
self.fips || self.fips_precompiled || self.fips_link_precompiled
|
self.fips
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Env {
|
impl Env {
|
||||||
fn from_env(target: &str, host: &str, is_fips_like: bool) -> Self {
|
fn from_env(host: &str, target: &str, is_fips_like: bool) -> Self {
|
||||||
const NORMAL_PREFIX: &str = "BORING_BSSL";
|
const NORMAL_PREFIX: &str = "BORING_BSSL";
|
||||||
const FIPS_PREFIX: &str = "BORING_BSSL_FIPS";
|
const FIPS_PREFIX: &str = "BORING_BSSL_FIPS";
|
||||||
|
|
||||||
|
let var_prefix = if host == target { "HOST" } else { "TARGET" };
|
||||||
let target_with_underscores = target.replace('-', "_");
|
let target_with_underscores = target.replace('-', "_");
|
||||||
|
|
||||||
// Logic stolen from cmake-rs.
|
let target_only_var = |name: &str| {
|
||||||
let target_var = |name: &str| {
|
|
||||||
let kind = if host == target { "HOST" } else { "TARGET" };
|
|
||||||
|
|
||||||
// TODO(rmehra): look for just `name` first, as most people just set that
|
|
||||||
var(&format!("{name}_{target}"))
|
var(&format!("{name}_{target}"))
|
||||||
.or_else(|| var(&format!("{name}_{target_with_underscores}")))
|
.or_else(|| var(&format!("{name}_{target_with_underscores}")))
|
||||||
.or_else(|| var(&format!("{kind}_{name}")))
|
.or_else(|| var(&format!("{var_prefix}_{name}")))
|
||||||
.or_else(|| var(name))
|
|
||||||
};
|
};
|
||||||
|
let target_var = |name: &str| target_only_var(name).or_else(|| var(name));
|
||||||
|
|
||||||
let boringssl_var = |name: &str| {
|
let boringssl_var = |name: &str| {
|
||||||
// The passed name is the non-fips version of the environment variable,
|
// The passed name is the non-fips version of the environment variable,
|
||||||
|
|
@ -175,7 +149,6 @@ impl Env {
|
||||||
path: boringssl_var("BORING_BSSL_PATH").map(PathBuf::from),
|
path: boringssl_var("BORING_BSSL_PATH").map(PathBuf::from),
|
||||||
include_path: boringssl_var("BORING_BSSL_INCLUDE_PATH").map(PathBuf::from),
|
include_path: boringssl_var("BORING_BSSL_INCLUDE_PATH").map(PathBuf::from),
|
||||||
source_path: boringssl_var("BORING_BSSL_SOURCE_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")
|
assume_patched: boringssl_var("BORING_BSSL_ASSUME_PATCHED")
|
||||||
.is_some_and(|v| !v.is_empty()),
|
.is_some_and(|v| !v.is_empty()),
|
||||||
sysroot: boringssl_var("BORING_BSSL_SYSROOT").map(PathBuf::from),
|
sysroot: boringssl_var("BORING_BSSL_SYSROOT").map(PathBuf::from),
|
||||||
|
|
@ -186,6 +159,9 @@ impl Env {
|
||||||
android_ndk_home: target_var("ANDROID_NDK_HOME").map(Into::into),
|
android_ndk_home: target_var("ANDROID_NDK_HOME").map(Into::into),
|
||||||
cmake_toolchain_file: target_var("CMAKE_TOOLCHAIN_FILE").map(Into::into),
|
cmake_toolchain_file: target_var("CMAKE_TOOLCHAIN_FILE").map(Into::into),
|
||||||
cpp_runtime_lib: target_var("BORING_BSSL_RUST_CPPLIB"),
|
cpp_runtime_lib: target_var("BORING_BSSL_RUST_CPPLIB"),
|
||||||
|
// matches the `cc` crate
|
||||||
|
cc: target_only_var("CC"),
|
||||||
|
cxx: target_only_var("CXX"),
|
||||||
docs_rs: var("DOCS_RS").is_some(),
|
docs_rs: var("DOCS_RS").is_some(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[
|
||||||
&[
|
&[
|
||||||
("CMAKE_OSX_ARCHITECTURES", "arm64"),
|
("CMAKE_OSX_ARCHITECTURES", "arm64"),
|
||||||
("CMAKE_OSX_SYSROOT", "iphoneos"),
|
("CMAKE_OSX_SYSROOT", "iphoneos"),
|
||||||
|
("CMAKE_MACOSX_BUNDLE", "OFF"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -57,6 +58,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[
|
||||||
&[
|
&[
|
||||||
("CMAKE_OSX_ARCHITECTURES", "arm64"),
|
("CMAKE_OSX_ARCHITECTURES", "arm64"),
|
||||||
("CMAKE_OSX_SYSROOT", "iphonesimulator"),
|
("CMAKE_OSX_SYSROOT", "iphonesimulator"),
|
||||||
|
("CMAKE_MACOSX_BUNDLE", "OFF"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -64,6 +66,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[
|
||||||
&[
|
&[
|
||||||
("CMAKE_OSX_ARCHITECTURES", "x86_64"),
|
("CMAKE_OSX_ARCHITECTURES", "x86_64"),
|
||||||
("CMAKE_OSX_SYSROOT", "iphonesimulator"),
|
("CMAKE_OSX_SYSROOT", "iphonesimulator"),
|
||||||
|
("CMAKE_MACOSX_BUNDLE", "OFF"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// macOS
|
// macOS
|
||||||
|
|
@ -114,11 +117,7 @@ fn get_boringssl_source_path(config: &Config) -> &PathBuf {
|
||||||
static SOURCE_PATH: OnceLock<PathBuf> = OnceLock::new();
|
static SOURCE_PATH: OnceLock<PathBuf> = OnceLock::new();
|
||||||
|
|
||||||
SOURCE_PATH.get_or_init(|| {
|
SOURCE_PATH.get_or_init(|| {
|
||||||
let submodule_dir = if config.features.fips {
|
let submodule_dir = "boringssl";
|
||||||
"boringssl-fips"
|
|
||||||
} else {
|
|
||||||
"boringssl"
|
|
||||||
};
|
|
||||||
|
|
||||||
let src_path = config.out_dir.join(submodule_dir);
|
let src_path = config.out_dir.join(submodule_dir);
|
||||||
|
|
||||||
|
|
@ -152,7 +151,7 @@ fn get_boringssl_source_path(config: &Config) -> &PathBuf {
|
||||||
///
|
///
|
||||||
/// MSVC generator on Windows place static libs in a target sub-folder,
|
/// MSVC generator on Windows place static libs in a target sub-folder,
|
||||||
/// so adjust library location based on platform and build target.
|
/// so adjust library location based on platform and build target.
|
||||||
/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
|
/// See issue: <https://github.com/alexcrichton/cmake-rs/issues/18>
|
||||||
fn get_boringssl_platform_output_path(config: &Config) -> String {
|
fn get_boringssl_platform_output_path(config: &Config) -> String {
|
||||||
if config.target.ends_with("-msvc") {
|
if config.target.ends_with("-msvc") {
|
||||||
// Code under this branch should match the logic in cmake-rs
|
// Code under this branch should match the logic in cmake-rs
|
||||||
|
|
@ -193,7 +192,7 @@ fn get_boringssl_platform_output_path(config: &Config) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new cmake::Config for building BoringSSL.
|
/// Returns a new `cmake::Config` for building BoringSSL.
|
||||||
///
|
///
|
||||||
/// It will add platform-specific parameters if needed.
|
/// It will add platform-specific parameters if needed.
|
||||||
fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
|
fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
|
||||||
|
|
@ -216,6 +215,15 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
|
||||||
.define("CMAKE_ASM_COMPILER_TARGET", &config.target);
|
.define("CMAKE_ASM_COMPILER_TARGET", &config.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !config.features.fips {
|
||||||
|
if let Some(cc) = &config.env.cc {
|
||||||
|
boringssl_cmake.define("CMAKE_C_COMPILER", cc);
|
||||||
|
}
|
||||||
|
if let Some(cxx) = &config.env.cxx {
|
||||||
|
boringssl_cmake.define("CMAKE_CXX_COMPILER", cxx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(sysroot) = &config.env.sysroot {
|
if let Some(sysroot) = &config.env.sysroot {
|
||||||
boringssl_cmake.define("CMAKE_SYSROOT", sysroot);
|
boringssl_cmake.define("CMAKE_SYSROOT", sysroot);
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +303,7 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
|
||||||
config
|
config
|
||||||
.manifest_dir
|
.manifest_dir
|
||||||
.join(src_path)
|
.join(src_path)
|
||||||
.join("src/util/32-bit-toolchain.cmake")
|
.join("util/32-bit-toolchain.cmake")
|
||||||
.as_os_str(),
|
.as_os_str(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -331,55 +339,6 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
|
||||||
boringssl_cmake
|
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) -> Option<String> {
|
|
||||||
let output = match Command::new(tool).arg("--version").output() {
|
|
||||||
Ok(o) => o,
|
|
||||||
Err(e) => {
|
|
||||||
println!("cargo:warning=missing {tool}, trying other compilers: {e}");
|
|
||||||
// NOTE: hard-codes that the loop below checks the version
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if !output.status.success() {
|
|
||||||
return Some(String::new());
|
|
||||||
}
|
|
||||||
let output = std::str::from_utf8(&output.stdout).expect("invalid utf8 output");
|
|
||||||
Some(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 (Some(cc_version), Some(cxx_version)) = (version(cc), version(cxx)) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
if cc_version.contains(REQUIRED_CLANG_VERSION) {
|
|
||||||
assert!(
|
|
||||||
cxx_version.contains(REQUIRED_CLANG_VERSION),
|
|
||||||
"mismatched versions of cc and c++"
|
|
||||||
);
|
|
||||||
return (cc, cxx);
|
|
||||||
} else if cc == "cc" {
|
|
||||||
panic!(
|
|
||||||
"unsupported clang version \"{cc_version}\": FIPS requires clang {REQUIRED_CLANG_VERSION}"
|
|
||||||
);
|
|
||||||
} else if !cc_version.is_empty() {
|
|
||||||
println!(
|
|
||||||
"cargo:warning=FIPS requires clang version {REQUIRED_CLANG_VERSION}, skipping incompatible version \"{cc_version}\""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pick_best_android_ndk_toolchain(toolchains_dir: &Path) -> std::io::Result<OsString> {
|
fn pick_best_android_ndk_toolchain(toolchains_dir: &Path) -> std::io::Result<OsString> {
|
||||||
let toolchains = std::fs::read_dir(toolchains_dir)?.collect::<Result<Vec<_>, _>>()?;
|
let toolchains = std::fs::read_dir(toolchains_dir)?.collect::<Result<Vec<_>, _>>()?;
|
||||||
// First look for one of the toolchains that Google has documented.
|
// First look for one of the toolchains that Google has documented.
|
||||||
|
|
@ -475,14 +434,12 @@ fn ensure_patches_applied(config: &Config) -> io::Result<()> {
|
||||||
);
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else if config.env.source_path.is_some()
|
} else if config.env.source_path.is_some()
|
||||||
&& (config.features.rpk
|
&& (config.features.rpk || config.features.underscore_wildcards)
|
||||||
|| config.features.pq_experimental
|
|
||||||
|| config.features.underscore_wildcards)
|
|
||||||
{
|
{
|
||||||
panic!(
|
panic!(
|
||||||
"BORING_BSSL_ASSUME_PATCHED must be set when setting
|
"BORING_BSSL_ASSUME_PATCHED must be set when setting
|
||||||
BORING_BSSL_SOURCE_PATH and using any of the following
|
BORING_BSSL_SOURCE_PATH and using any of the following
|
||||||
features: rpk, pq-experimental, underscore-wildcards"
|
features: rpk, underscore-wildcards"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,66 +538,17 @@ fn built_boring_source_path(config: &Config) -> &PathBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.features.fips {
|
if config.features.fips {
|
||||||
let (clang, clangxx) = verify_fips_clang_version();
|
cfg.define("CMAKE_C_COMPILER", "clang")
|
||||||
cfg.define("CMAKE_C_COMPILER", clang)
|
.define("CMAKE_CXX_COMPILER", "clang++")
|
||||||
.define("CMAKE_CXX_COMPILER", clangxx)
|
.define("CMAKE_ASM_COMPILER", "clang")
|
||||||
.define("CMAKE_ASM_COMPILER", clang)
|
|
||||||
.define("FIPS", "1");
|
.define("FIPS", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.features.fips_link_precompiled {
|
|
||||||
cfg.define("FIPS", "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.build_target("ssl").build();
|
cfg.build_target("ssl").build();
|
||||||
cfg.build_target("crypto").build()
|
cfg.build_target("crypto").build()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link_in_precompiled_bcm_o(config: &Config) {
|
|
||||||
println!("cargo:warning=linking in precompiled `bcm.o` module");
|
|
||||||
|
|
||||||
let bssl_dir = built_boring_source_path(config);
|
|
||||||
let bcm_o_src_path = config.env.precompiled_bcm_o.as_ref()
|
|
||||||
.expect("`fips-link-precompiled` requires `BORING_BSSL_FIPS_PRECOMPILED_BCM_O` env variable to be specified");
|
|
||||||
|
|
||||||
let libcrypto_path = bssl_dir
|
|
||||||
.join("build/crypto/libcrypto.a")
|
|
||||||
.canonicalize()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let bcm_o_dst_path = 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")
|
|
||||||
.arg("t")
|
|
||||||
.arg(&libcrypto_path)
|
|
||||||
.arg("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"])
|
|
||||||
.args([&libcrypto_path, &bcm_o_dst_path]),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_cpp_runtime_lib(config: &Config) -> Option<String> {
|
fn get_cpp_runtime_lib(config: &Config) -> Option<String> {
|
||||||
if let Some(ref cpp_lib) = config.env.cpp_runtime_lib {
|
if let Some(ref cpp_lib) = config.env.cpp_runtime_lib {
|
||||||
return cpp_lib.clone().into_string().ok();
|
return cpp_lib.clone().into_string().ok();
|
||||||
|
|
@ -699,10 +607,6 @@ fn emit_link_directives(config: &Config) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.features.fips_link_precompiled {
|
|
||||||
link_in_precompiled_bcm_o(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(cpp_lib) = get_cpp_runtime_lib(config) {
|
if let Some(cpp_lib) = get_cpp_runtime_lib(config) {
|
||||||
println!("cargo:rustc-link-lib={cpp_lib}");
|
println!("cargo:rustc-link-lib={cpp_lib}");
|
||||||
}
|
}
|
||||||
|
|
@ -731,12 +635,8 @@ fn generate_bindings(config: &Config) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// bindgen 0.70 replaced the run-time layout tests with compile-time ones,
|
let target_rust_version =
|
||||||
// but they depend on std::mem::offset_of, stabilized in 1.77.
|
bindgen::RustTarget::stable(77, 0).expect("bindgen does not recognize target rust version");
|
||||||
let supports_layout_tests = autocfg::new().probe_rustc_version(1, 77);
|
|
||||||
let Ok(target_rust_version) = bindgen::RustTarget::stable(68, 0) else {
|
|
||||||
panic!("bindgen does not recognize target rust version");
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut builder = bindgen::Builder::default()
|
let mut builder = bindgen::Builder::default()
|
||||||
.rust_target(target_rust_version) // bindgen MSRV is 1.70, so this is enough
|
.rust_target(target_rust_version) // bindgen MSRV is 1.70, so this is enough
|
||||||
|
|
@ -752,7 +652,7 @@ fn generate_bindings(config: &Config) {
|
||||||
.generate_comments(true)
|
.generate_comments(true)
|
||||||
.fit_macro_constants(false)
|
.fit_macro_constants(false)
|
||||||
.size_t_is_usize(true)
|
.size_t_is_usize(true)
|
||||||
.layout_tests(supports_layout_tests)
|
.layout_tests(config.env.debug.is_some())
|
||||||
.prepend_enum_name(true)
|
.prepend_enum_name(true)
|
||||||
.blocklist_type("max_align_t") // Not supported by bindgen on all targets, not used by BoringSSL
|
.blocklist_type("max_align_t") // Not supported by bindgen on all targets, not used by BoringSSL
|
||||||
.clang_args(get_extra_clang_args_for_bindgen(config))
|
.clang_args(get_extra_clang_args_for_bindgen(config))
|
||||||
|
|
@ -779,7 +679,6 @@ fn generate_bindings(config: &Config) {
|
||||||
"des.h",
|
"des.h",
|
||||||
"dtls1.h",
|
"dtls1.h",
|
||||||
"hkdf.h",
|
"hkdf.h",
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
"hpke.h",
|
"hpke.h",
|
||||||
"hmac.h",
|
"hmac.h",
|
||||||
"hrss.h",
|
"hrss.h",
|
||||||
|
|
@ -804,7 +703,24 @@ fn generate_bindings(config: &Config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let bindings = builder.generate().expect("Unable to generate bindings");
|
let bindings = builder.generate().expect("Unable to generate bindings");
|
||||||
|
let mut source_code = Vec::new();
|
||||||
bindings
|
bindings
|
||||||
.write_to_file(config.out_dir.join("bindings.rs"))
|
.write(Box::new(&mut source_code))
|
||||||
.expect("Couldn't write bindings!");
|
.expect("Couldn't serialize bindings!");
|
||||||
|
ensure_err_lib_enum_is_named(&mut source_code);
|
||||||
|
fs::write(config.out_dir.join("bindings.rs"), source_code).expect("Couldn't write bindings!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// err.h has anonymous `enum { ERR_LIB_NONE = 1 }`, which makes a dodgy `_bindgen_ty_1` name
|
||||||
|
fn ensure_err_lib_enum_is_named(source_code: &mut Vec<u8>) {
|
||||||
|
let src = String::from_utf8_lossy(source_code);
|
||||||
|
let enum_type = src
|
||||||
|
.split_once("ERR_LIB_SSL:")
|
||||||
|
.and_then(|(_, def)| Some(def.split_once("=")?.0))
|
||||||
|
.unwrap_or("_bindgen_ty_1");
|
||||||
|
|
||||||
|
source_code.extend_from_slice(
|
||||||
|
format!("\n/// Newtype for [`ERR_LIB_SSL`] constants\npub use {enum_type} as ErrLib;\n")
|
||||||
|
.as_bytes(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,21 +1,10 @@
|
||||||
https://github.com/google/boringssl/compare/master...cloudflare:boringssl:underscore-wildcards
|
https://github.com/google/boringssl/compare/master...cloudflare:boringssl:underscore-wildcards
|
||||||
|
|
||||||
--- a/src/crypto/x509v3/v3_utl.c
|
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
|
||||||
+++ b/src/crypto/x509v3/v3_utl.c
|
index 9699b5a75..b0e9b34a6 100644
|
||||||
@@ -790,7 +790,9 @@ static int wildcard_match(const unsigned char *prefix, size_t prefix_len,
|
--- a/crypto/x509/x509_test.cc
|
||||||
// Check that the part matched by the wildcard contains only
|
+++ b/crypto/x509/x509_test.cc
|
||||||
// permitted characters and only matches a single label.
|
@@ -4420,6 +4420,31 @@ TEST(X509Test, Names) {
|
||||||
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=*/{},
|
/*invalid_emails=*/{},
|
||||||
/*flags=*/0,
|
/*flags=*/0,
|
||||||
},
|
},
|
||||||
|
|
@ -47,9 +36,26 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:unders
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
--- a/src/include/openssl/x509c3.h
|
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
|
||||||
+++ b/src/include/openssl/x509v3.h
|
index bbc82e283..e61e1901d 100644
|
||||||
@@ -4497,6 +4497,8 @@ OPENSSL_EXPORT int X509_PURPOSE_get_id(const X509_PURPOSE *);
|
--- a/crypto/x509v3/v3_utl.c
|
||||||
|
+++ b/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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h
|
||||||
|
index 2a2e02c2e..24e0604b0 100644
|
||||||
|
--- a/include/openssl/x509v3.h
|
||||||
|
+++ b/include/openssl/x509v3.h
|
||||||
|
@@ -939,6 +939,8 @@ OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x);
|
||||||
#define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0
|
#define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0
|
||||||
// Skip the subject common name fallback if subjectAltNames is missing.
|
// Skip the subject common name fallback if subjectAltNames is missing.
|
||||||
#define X509_CHECK_FLAG_NEVER_CHECK_SUBJECT 0x20
|
#define X509_CHECK_FLAG_NEVER_CHECK_SUBJECT 0x20
|
||||||
|
|
@ -58,4 +64,3 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:unders
|
||||||
|
|
||||||
OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen,
|
OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen,
|
||||||
unsigned int flags, char **peername);
|
unsigned int flags, char **peername);
|
||||||
--
|
|
||||||
|
|
|
||||||
|
|
@ -13,70 +13,25 @@ edition = { workspace = true }
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["pq-experimental", "underscore-wildcards"]
|
features = ["underscore-wildcards"]
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Controlling the build
|
# Controlling the build
|
||||||
|
|
||||||
# NOTE: This feature is deprecated. It is needed for the submoduled
|
|
||||||
# boringssl-fips, which is extremely old and requires modifications to the
|
|
||||||
# bindings, as some newer APIs don't exist and some function signatures have
|
|
||||||
# changed. It is highly recommended to use `fips-precompiled` instead.
|
|
||||||
#
|
|
||||||
# This feature sets `fips-compat` on behalf of the user to guarantee bindings
|
|
||||||
# compatibility with the submoduled boringssl-fips.
|
|
||||||
#
|
|
||||||
# Use a FIPS-validated version of BoringSSL.
|
# Use a FIPS-validated version of BoringSSL.
|
||||||
fips = ["fips-compat", "boring-sys/fips"]
|
fips = ["boring-sys/fips"]
|
||||||
|
|
||||||
# Build with compatibility for the submoduled boringssl-fips, without enabling
|
# **DO NOT USE** This will be removed without warning in future releases.
|
||||||
# the `fips` feature itself (useful e.g. if `fips-link-precompiled` is used
|
legacy-compat-deprecated = []
|
||||||
# with an older BoringSSL version).
|
|
||||||
fips-compat = []
|
|
||||||
|
|
||||||
# Use a precompiled FIPS-validated version of BoringSSL. Meant to be used with
|
# Applies a patch to enable `ffi::X509_CHECK_FLAG_UNDERSCORE_WILDCARDS`. This
|
||||||
# FIPS-20230428 or newer. Users must set `BORING_BSSL_FIPS_PATH` to use this
|
# feature is necessary in order to compile the bindings for the default branch
|
||||||
# feature, or else the build will fail.
|
# of boringSSL. Alternatively, a version of boringSSL that implements the same
|
||||||
fips-precompiled = ["boring-sys/fips-precompiled"]
|
# feature set can be provided by setting `BORING_BSSL{,_FIPS}_SOURCE_PATH` and
|
||||||
|
# `BORING_BSSL{,_FIPS}_ASSUME_PATCHED`.
|
||||||
# Link with precompiled FIPS-validated `bcm.o` module.
|
|
||||||
fips-link-precompiled = ["boring-sys/fips-link-precompiled"]
|
|
||||||
|
|
||||||
# Applies a patch to the boringSSL source code that enables support for PQ key
|
|
||||||
# exchange. This feature is necessary in order to compile the bindings for the
|
|
||||||
# default branch of boringSSL. Alternatively, a version of boringSSL that
|
|
||||||
# implements the same feature set can be provided by setting
|
|
||||||
# `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"]
|
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
|
|
||||||
# choosing their own preferences.
|
|
||||||
kx-safe-default = []
|
|
||||||
|
|
||||||
# Support PQ key exchange. The client will prefer classical key exchange, but
|
|
||||||
# will upgrade to PQ key exchange if requested by the server. This is the
|
|
||||||
# safest option if you don't know if the peer supports PQ key exchange. This
|
|
||||||
# feature implies "kx-safe-default".
|
|
||||||
kx-client-pq-supported = ["kx-safe-default"]
|
|
||||||
|
|
||||||
# Prefer PQ key exchange. The client will prefer PQ exchange, but fallback to
|
|
||||||
# classical key exchange if requested by the server. This is the best option if
|
|
||||||
# you know the peer supports PQ key exchange. This feature implies
|
|
||||||
# "kx-safe-default" and "kx-client-pq-supported".
|
|
||||||
kx-client-pq-preferred = ["kx-safe-default", "kx-client-pq-supported"]
|
|
||||||
|
|
||||||
# Disable key exchange involving non-NIST key exchange on the client side.
|
|
||||||
# Implies "kx-safe-default".
|
|
||||||
kx-client-nist-required = ["kx-safe-default"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = { workspace = true }
|
bitflags = { workspace = true }
|
||||||
foreign-types = { workspace = true }
|
foreign-types = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -43,18 +43,19 @@ fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> {
|
||||||
let not_after = Asn1Time::days_from_now(365)?;
|
let not_after = Asn1Time::days_from_now(365)?;
|
||||||
cert_builder.set_not_after(¬_after)?;
|
cert_builder.set_not_after(¬_after)?;
|
||||||
|
|
||||||
cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?;
|
cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?.as_ref())?;
|
||||||
cert_builder.append_extension(
|
cert_builder.append_extension(
|
||||||
KeyUsage::new()
|
KeyUsage::new()
|
||||||
.critical()
|
.critical()
|
||||||
.key_cert_sign()
|
.key_cert_sign()
|
||||||
.crl_sign()
|
.crl_sign()
|
||||||
.build()?,
|
.build()?
|
||||||
|
.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let subject_key_identifier =
|
let subject_key_identifier =
|
||||||
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
|
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
|
||||||
cert_builder.append_extension(subject_key_identifier)?;
|
cert_builder.append_extension(&subject_key_identifier)?;
|
||||||
|
|
||||||
cert_builder.sign(&privkey, MessageDigest::sha256())?;
|
cert_builder.sign(&privkey, MessageDigest::sha256())?;
|
||||||
let cert = cert_builder.build();
|
let cert = cert_builder.build();
|
||||||
|
|
@ -106,7 +107,7 @@ fn mk_ca_signed_cert(
|
||||||
let not_after = Asn1Time::days_from_now(365)?;
|
let not_after = Asn1Time::days_from_now(365)?;
|
||||||
cert_builder.set_not_after(¬_after)?;
|
cert_builder.set_not_after(¬_after)?;
|
||||||
|
|
||||||
cert_builder.append_extension(BasicConstraints::new().build()?)?;
|
cert_builder.append_extension(BasicConstraints::new().build()?.as_ref())?;
|
||||||
|
|
||||||
cert_builder.append_extension(
|
cert_builder.append_extension(
|
||||||
KeyUsage::new()
|
KeyUsage::new()
|
||||||
|
|
@ -114,24 +115,25 @@ fn mk_ca_signed_cert(
|
||||||
.non_repudiation()
|
.non_repudiation()
|
||||||
.digital_signature()
|
.digital_signature()
|
||||||
.key_encipherment()
|
.key_encipherment()
|
||||||
.build()?,
|
.build()?
|
||||||
|
.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let subject_key_identifier =
|
let subject_key_identifier =
|
||||||
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
|
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
|
||||||
cert_builder.append_extension(subject_key_identifier)?;
|
cert_builder.append_extension(&subject_key_identifier)?;
|
||||||
|
|
||||||
let auth_key_identifier = AuthorityKeyIdentifier::new()
|
let auth_key_identifier = AuthorityKeyIdentifier::new()
|
||||||
.keyid(false)
|
.keyid(false)
|
||||||
.issuer(false)
|
.issuer(false)
|
||||||
.build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
|
.build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
|
||||||
cert_builder.append_extension(auth_key_identifier)?;
|
cert_builder.append_extension(&auth_key_identifier)?;
|
||||||
|
|
||||||
let subject_alt_name = SubjectAlternativeName::new()
|
let subject_alt_name = SubjectAlternativeName::new()
|
||||||
.dns("*.example.com")
|
.dns("*.example.com")
|
||||||
.dns("hello.com")
|
.dns("hello.com")
|
||||||
.build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
|
.build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
|
||||||
cert_builder.append_extension(subject_alt_name)?;
|
cert_builder.append_extension(&subject_alt_name)?;
|
||||||
|
|
||||||
cert_builder.sign(ca_privkey, MessageDigest::sha256())?;
|
cert_builder.sign(ca_privkey, MessageDigest::sha256())?;
|
||||||
let cert = cert_builder.build();
|
let cert = cert_builder.build();
|
||||||
|
|
@ -147,7 +149,7 @@ fn real_main() -> Result<(), ErrorStack> {
|
||||||
match ca_cert.issued(&cert) {
|
match ca_cert.issued(&cert) {
|
||||||
Ok(()) => println!("Certificate verified!"),
|
Ok(()) => println!("Certificate verified!"),
|
||||||
Err(ver_err) => println!("Failed to verify certificate: {ver_err}"),
|
Err(ver_err) => println!("Failed to verify certificate: {ver_err}"),
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -156,5 +158,5 @@ fn main() {
|
||||||
match real_main() {
|
match real_main() {
|
||||||
Ok(()) => println!("Finished."),
|
Ok(()) => println!("Finished."),
|
||||||
Err(e) => println!("Error: {e}"),
|
Err(e) => println!("Error: {e}"),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,20 +63,19 @@ foreign_type_and_impl_send_sync! {
|
||||||
|
|
||||||
impl fmt::Display for Asn1GeneralizedTimeRef {
|
impl fmt::Display for Asn1GeneralizedTimeRef {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
unsafe {
|
let bio = MemBio::new().ok();
|
||||||
let mem_bio = match MemBio::new() {
|
let msg = bio
|
||||||
Err(_) => return f.write_str("error"),
|
.as_ref()
|
||||||
Ok(m) => m,
|
.and_then(|mem_bio| unsafe {
|
||||||
};
|
cvt(ffi::ASN1_GENERALIZEDTIME_print(
|
||||||
let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print(
|
mem_bio.as_ptr(),
|
||||||
mem_bio.as_ptr(),
|
self.as_ptr(),
|
||||||
self.as_ptr(),
|
))
|
||||||
));
|
.ok()?;
|
||||||
match print_result {
|
str::from_utf8(mem_bio.get_buf()).ok()
|
||||||
Err(_) => f.write_str("error"),
|
})
|
||||||
Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
|
.unwrap_or("error");
|
||||||
}
|
f.write_str(msg)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -528,7 +527,20 @@ impl Asn1BitStringRef {
|
||||||
#[corresponds(ASN1_STRING_get0_data)]
|
#[corresponds(ASN1_STRING_get0_data)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
|
unsafe {
|
||||||
|
let ptr = ASN1_STRING_get0_data(self.as_ptr().cast());
|
||||||
|
if ptr.is_null() {
|
||||||
|
return &[];
|
||||||
|
}
|
||||||
|
slice::from_raw_parts(ptr, self.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the Asn1BitString as a str, if possible.
|
||||||
|
#[corresponds(ASN1_STRING_get0_data)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn to_str(&self) -> Option<&str> {
|
||||||
|
str::from_utf8(self.as_slice()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of bytes in the string.
|
/// Returns the number of bytes in the string.
|
||||||
|
|
@ -601,10 +613,11 @@ impl fmt::Display for Asn1ObjectRef {
|
||||||
self.as_ptr(),
|
self.as_ptr(),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
match str::from_utf8(&buf[..len as usize]) {
|
fmt.write_str(
|
||||||
Err(_) => fmt.write_str("error"),
|
buf.get(..len as usize)
|
||||||
Ok(s) => fmt.write_str(s),
|
.and_then(|s| str::from_utf8(s).ok())
|
||||||
}
|
.unwrap_or("error"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ impl Drop for MemBioSlice<'_> {
|
||||||
|
|
||||||
impl<'a> MemBioSlice<'a> {
|
impl<'a> MemBioSlice<'a> {
|
||||||
pub fn new(buf: &'a [u8]) -> Result<MemBioSlice<'a>, ErrorStack> {
|
pub fn new(buf: &'a [u8]) -> Result<MemBioSlice<'a>, ErrorStack> {
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
#[cfg(not(feature = "legacy-compat-deprecated"))]
|
||||||
type BufLen = isize;
|
type BufLen = isize;
|
||||||
#[cfg(feature = "fips-compat")]
|
#[cfg(feature = "legacy-compat-deprecated")]
|
||||||
type BufLen = libc::c_int;
|
type BufLen = libc::c_int;
|
||||||
|
|
||||||
ffi::init();
|
ffi::init();
|
||||||
|
|
@ -68,7 +68,10 @@ impl MemBio {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ptr = ptr::null_mut();
|
let mut ptr = ptr::null_mut();
|
||||||
let len = ffi::BIO_get_mem_data(self.0, &mut ptr);
|
let len = ffi::BIO_get_mem_data(self.0, &mut ptr);
|
||||||
slice::from_raw_parts(ptr as *const _ as *const _, len as usize)
|
if ptr.is_null() {
|
||||||
|
return &[];
|
||||||
|
}
|
||||||
|
slice::from_raw_parts(ptr.cast_const().cast(), len as usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
to_der! {
|
to_der! {
|
||||||
/// Serializes the parameters into a DER-encoded PKCS#3 DHparameter structure.
|
/// Serializes the parameters into a DER-encoded PKCS#3 `DHparameter` structure.
|
||||||
#[corresponds(i2d_DHparams)]
|
#[corresponds(i2d_DHparams)]
|
||||||
params_to_der,
|
params_to_der,
|
||||||
ffi::i2d_DHparams
|
ffi::i2d_DHparams
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use openssl_macros::corresponds;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
use std::ffi::CString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
@ -27,6 +28,8 @@ use std::str;
|
||||||
|
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
|
||||||
|
pub use crate::ffi::ErrLib;
|
||||||
|
|
||||||
/// Collection of [`Error`]s from OpenSSL.
|
/// Collection of [`Error`]s from OpenSSL.
|
||||||
///
|
///
|
||||||
/// [`Error`]: struct.Error.html
|
/// [`Error`]: struct.Error.html
|
||||||
|
|
@ -35,6 +38,9 @@ pub struct ErrorStack(Vec<Error>);
|
||||||
|
|
||||||
impl ErrorStack {
|
impl ErrorStack {
|
||||||
/// Pops the contents of the OpenSSL error stack, and returns it.
|
/// Pops the contents of the OpenSSL error stack, and returns it.
|
||||||
|
///
|
||||||
|
/// This should be used only immediately after calling Boring FFI functions,
|
||||||
|
/// otherwise the stack may be empty or a leftover from unrelated calls.
|
||||||
#[corresponds(ERR_get_error_line_data)]
|
#[corresponds(ERR_get_error_line_data)]
|
||||||
#[must_use = "Use ErrorStack::clear() to drop the error stack"]
|
#[must_use = "Use ErrorStack::clear() to drop the error stack"]
|
||||||
pub fn get() -> ErrorStack {
|
pub fn get() -> ErrorStack {
|
||||||
|
|
@ -56,7 +62,13 @@ impl ErrorStack {
|
||||||
/// Used to report errors from the Rust crate
|
/// Used to report errors from the Rust crate
|
||||||
#[cold]
|
#[cold]
|
||||||
pub(crate) fn internal_error(err: impl error::Error) -> Self {
|
pub(crate) fn internal_error(err: impl error::Error) -> Self {
|
||||||
Self(vec![Error::new_internal(err.to_string())])
|
Self(vec![Error::new_internal(Data::String(err.to_string()))])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to report errors from the Rust crate
|
||||||
|
#[cold]
|
||||||
|
pub(crate) fn internal_error_str(message: &'static str) -> Self {
|
||||||
|
Self(vec![Error::new_internal(Data::Static(message))])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Empties the current thread's error queue.
|
/// Empties the current thread's error queue.
|
||||||
|
|
@ -91,7 +103,7 @@ impl fmt::Display for ErrorStack {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
"[{}]",
|
"[{}]",
|
||||||
err.reason_internal()
|
err.reason()
|
||||||
.or_else(|| err.library())
|
.or_else(|| err.library())
|
||||||
.unwrap_or("unknown reason")
|
.unwrap_or("unknown reason")
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -120,7 +132,15 @@ pub struct Error {
|
||||||
code: c_uint,
|
code: c_uint,
|
||||||
file: *const c_char,
|
file: *const c_char,
|
||||||
line: c_uint,
|
line: c_uint,
|
||||||
data: Option<Cow<'static, str>>,
|
data: Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum Data {
|
||||||
|
None,
|
||||||
|
CString(CString),
|
||||||
|
String(String),
|
||||||
|
Static(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Sync for Error {}
|
unsafe impl Sync for Error {}
|
||||||
|
|
@ -146,11 +166,9 @@ impl Error {
|
||||||
// The memory referenced by data is only valid until that slot is overwritten
|
// The memory referenced by data is only valid until that slot is overwritten
|
||||||
// in the error stack, so we'll need to copy it off if it's dynamic
|
// in the error stack, so we'll need to copy it off if it's dynamic
|
||||||
let data = if flags & ffi::ERR_FLAG_STRING != 0 {
|
let data = if flags & ffi::ERR_FLAG_STRING != 0 {
|
||||||
let bytes = CStr::from_ptr(data as *const _).to_bytes();
|
Data::CString(CStr::from_ptr(data.cast()).to_owned())
|
||||||
let data = String::from_utf8_lossy(bytes).into_owned();
|
|
||||||
Some(data.into())
|
|
||||||
} else {
|
} else {
|
||||||
None
|
Data::None
|
||||||
};
|
};
|
||||||
Some(Error {
|
Some(Error {
|
||||||
code,
|
code,
|
||||||
|
|
@ -174,31 +192,29 @@ impl Error {
|
||||||
self.file,
|
self.file,
|
||||||
self.line,
|
self.line,
|
||||||
);
|
);
|
||||||
let ptr = match self.data {
|
if let Some(cstr) = self.data_cstr() {
|
||||||
Some(Cow::Borrowed(data)) => Some(data.as_ptr() as *mut c_char),
|
ffi::ERR_set_error_data(cstr.as_ptr().cast_mut(), ffi::ERR_FLAG_STRING);
|
||||||
Some(Cow::Owned(ref data)) => {
|
|
||||||
let ptr = ffi::OPENSSL_malloc((data.len() + 1) as _) as *mut c_char;
|
|
||||||
if ptr.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len());
|
|
||||||
*ptr.add(data.len()) = 0;
|
|
||||||
Some(ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
if let Some(ptr) = ptr {
|
|
||||||
ffi::ERR_add_error_data(1, ptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get `{lib}_R_{reason}` reason code for the given library, or `None` if the error is from a different library.
|
||||||
|
///
|
||||||
|
/// Libraries are identified by [`ERR_LIB_{name}`(ffi::ERR_LIB_SSL) constants.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
#[track_caller]
|
||||||
|
pub fn library_reason(&self, library_code: ErrLib) -> Option<c_int> {
|
||||||
|
debug_assert!(library_code.0 < ffi::ERR_NUM_LIBS.0);
|
||||||
|
(self.library_code() == library_code.0 as c_int).then_some(self.reason_code())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a raw OpenSSL **packed** error code for this error, which **can't be reliably compared to any error constant**.
|
/// Returns a raw OpenSSL **packed** error code for this error, which **can't be reliably compared to any error constant**.
|
||||||
///
|
///
|
||||||
/// Use [`Error::library_code()`] and [`Error::reason_code()`] instead.
|
/// Use [`Error::library_code()`] and [`Error::library_reason()`] instead.
|
||||||
/// Packed error codes are different than [SSL error codes](crate::ssl::ErrorCode).
|
/// Packed error codes are different than [SSL error codes](crate::ssl::ErrorCode).
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[deprecated(note = "use library_reason() to compare error codes")]
|
||||||
pub fn code(&self) -> c_uint {
|
pub fn code(&self) -> c_uint {
|
||||||
self.code
|
self.code
|
||||||
}
|
}
|
||||||
|
|
@ -214,14 +230,16 @@ impl Error {
|
||||||
if cstr.is_null() {
|
if cstr.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
CStr::from_ptr(cstr.cast())
|
||||||
str::from_utf8(bytes).ok()
|
.to_str()
|
||||||
|
.ok()
|
||||||
|
.filter(|&msg| msg != "unknown library")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the raw OpenSSL error constant for the library reporting the error (`ERR_LIB_{name}`).
|
/// Returns the raw OpenSSL error constant for the library reporting the error (`ERR_LIB_{name}`).
|
||||||
///
|
///
|
||||||
/// Error [reason codes](Error::reason_code) are not globally unique, but scoped to each library.
|
/// Error [reason codes](Error::library_reason) are not globally unique, but scoped to each library.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn library_code(&self) -> c_int {
|
pub fn library_code(&self) -> c_int {
|
||||||
ffi::ERR_GET_LIB(self.code)
|
ffi::ERR_GET_LIB(self.code)
|
||||||
|
|
@ -234,20 +252,23 @@ impl Error {
|
||||||
|
|
||||||
/// Returns the reason for the error.
|
/// Returns the reason for the error.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn reason(&self) -> Option<&'static str> {
|
pub fn reason(&self) -> Option<&str> {
|
||||||
|
if self.is_internal() {
|
||||||
|
return self.data();
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let cstr = ffi::ERR_reason_error_string(self.code);
|
let cstr = ffi::ERR_reason_error_string(self.code);
|
||||||
if cstr.is_null() {
|
if cstr.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
CStr::from_ptr(cstr.cast()).to_str().ok()
|
||||||
str::from_utf8(bytes).ok()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns [library-specific](Error::library_code) reason code corresponding to some of the `{lib}_R_{reason}` constants.
|
/// Returns [library-specific](Error::library_code) reason code corresponding to some of the `{lib}_R_{reason}` constants.
|
||||||
///
|
///
|
||||||
/// Reason codes are ambiguous, and different libraries reuse the same numeric values for different errors.
|
/// Reason codes are ambiguous, and different libraries reuse the same numeric values for different errors.
|
||||||
|
/// Use [`Error::library_reason`] to compare error codes.
|
||||||
///
|
///
|
||||||
/// For `ERR_LIB_SYS` the reason code is `errno`. `ERR_LIB_USER` can use any values.
|
/// For `ERR_LIB_SYS` the reason code is `errno`. `ERR_LIB_USER` can use any values.
|
||||||
/// Other libraries may use [`ERR_R_*`](ffi::ERR_R_FATAL) or their own codes.
|
/// Other libraries may use [`ERR_R_*`](ffi::ERR_R_FATAL) or their own codes.
|
||||||
|
|
@ -263,8 +284,9 @@ impl Error {
|
||||||
if self.file.is_null() {
|
if self.file.is_null() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
let bytes = CStr::from_ptr(self.file as *const _).to_bytes();
|
CStr::from_ptr(self.file.cast())
|
||||||
str::from_utf8(bytes).unwrap_or_default()
|
.to_str()
|
||||||
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,30 +302,37 @@ impl Error {
|
||||||
/// Returns additional data describing the error.
|
/// Returns additional data describing the error.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn data(&self) -> Option<&str> {
|
pub fn data(&self) -> Option<&str> {
|
||||||
self.data.as_deref()
|
match &self.data {
|
||||||
|
Data::None => None,
|
||||||
|
Data::CString(cstring) => cstring.to_str().ok(),
|
||||||
|
Data::String(s) => Some(s),
|
||||||
|
Data::Static(s) => Some(s),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_internal(msg: String) -> Self {
|
#[must_use]
|
||||||
|
fn data_cstr(&self) -> Option<Cow<'_, CStr>> {
|
||||||
|
let s = match &self.data {
|
||||||
|
Data::None => return None,
|
||||||
|
Data::CString(cstr) => return Some(Cow::Borrowed(cstr)),
|
||||||
|
Data::String(s) => s.as_str(),
|
||||||
|
Data::Static(s) => s,
|
||||||
|
};
|
||||||
|
CString::new(s).ok().map(Cow::Owned)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_internal(msg: Data) -> Self {
|
||||||
Self {
|
Self {
|
||||||
code: ffi::ERR_PACK(ffi::ERR_LIB_NONE.0 as _, 0, 0) as _,
|
code: ffi::ERR_PACK(ffi::ERR_LIB_NONE.0 as _, 0, 0) as _,
|
||||||
file: BORING_INTERNAL.as_ptr(),
|
file: BORING_INTERNAL.as_ptr(),
|
||||||
line: 0,
|
line: 0,
|
||||||
data: Some(msg.into()),
|
data: msg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_internal(&self) -> bool {
|
fn is_internal(&self) -> bool {
|
||||||
std::ptr::eq(self.file, BORING_INTERNAL.as_ptr())
|
std::ptr::eq(self.file, BORING_INTERNAL.as_ptr())
|
||||||
}
|
}
|
||||||
|
|
||||||
// reason() needs 'static
|
|
||||||
fn reason_internal(&self) -> Option<&str> {
|
|
||||||
if self.is_internal() {
|
|
||||||
self.data()
|
|
||||||
} else {
|
|
||||||
self.reason()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Error {
|
impl fmt::Debug for Error {
|
||||||
|
|
@ -334,7 +363,7 @@ impl fmt::Display for Error {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
"{}\n\nCode: {:08X}\nLoc: {}:{}",
|
"{}\n\nCode: {:08X}\nLoc: {}:{}",
|
||||||
self.reason_internal().unwrap_or("unknown TLS error"),
|
self.reason().unwrap_or("unknown TLS error"),
|
||||||
&self.code,
|
&self.code,
|
||||||
self.file(),
|
self.file(),
|
||||||
self.line()
|
self.line()
|
||||||
|
|
|
||||||
|
|
@ -15,16 +15,8 @@ pub fn enabled() -> bool {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_enabled() {
|
fn is_enabled() {
|
||||||
#[cfg(any(
|
#[cfg(feature = "fips")]
|
||||||
feature = "fips",
|
|
||||||
feature = "fips-precompiled",
|
|
||||||
feature = "fips-link-precompiled"
|
|
||||||
))]
|
|
||||||
assert!(enabled());
|
assert!(enabled());
|
||||||
#[cfg(not(any(
|
#[cfg(not(feature = "fips"))]
|
||||||
feature = "fips",
|
|
||||||
feature = "fips-precompiled",
|
|
||||||
feature = "fips-link-precompiled"
|
|
||||||
)))]
|
|
||||||
assert!(!enabled());
|
assert!(!enabled());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
use crate::cvt;
|
||||||
|
use crate::error::ErrorStack;
|
||||||
|
use crate::foreign_types::ForeignTypeRef;
|
||||||
|
use crate::hash::MessageDigest;
|
||||||
|
|
||||||
|
foreign_type_and_impl_send_sync! {
|
||||||
|
type CType = ffi::HMAC_CTX;
|
||||||
|
fn drop = ffi::HMAC_CTX_free;
|
||||||
|
|
||||||
|
pub struct HmacCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HmacCtxRef {
|
||||||
|
/// Configures HmacCtx to use `md` as the hash function and `key` as the key.
|
||||||
|
///
|
||||||
|
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/hmac.h.html#HMAC_Init_ex
|
||||||
|
pub fn init(&mut self, key: &[u8], md: &MessageDigest) -> Result<(), ErrorStack> {
|
||||||
|
ffi::init();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::HMAC_Init_ex(
|
||||||
|
self.as_ptr(),
|
||||||
|
key.as_ptr().cast(),
|
||||||
|
key.len(),
|
||||||
|
md.as_ptr(),
|
||||||
|
// ENGINE api is deprecated
|
||||||
|
core::ptr::null_mut(),
|
||||||
|
))
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -132,7 +132,7 @@ pub mod error;
|
||||||
pub mod ex_data;
|
pub mod ex_data;
|
||||||
pub mod fips;
|
pub mod fips;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
#[cfg(not(feature = "fips"))]
|
pub mod hmac;
|
||||||
pub mod hpke;
|
pub mod hpke;
|
||||||
pub mod memcmp;
|
pub mod memcmp;
|
||||||
pub mod nid;
|
pub mod nid;
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,9 @@ impl Nid {
|
||||||
pub fn long_name(&self) -> Result<&'static str, ErrorStack> {
|
pub fn long_name(&self) -> Result<&'static str, ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let nameptr = cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char)?;
|
let nameptr = cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char)?;
|
||||||
str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).map_err(ErrorStack::internal_error)
|
CStr::from_ptr(nameptr)
|
||||||
|
.to_str()
|
||||||
|
.map_err(ErrorStack::internal_error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +100,9 @@ impl Nid {
|
||||||
pub fn short_name(&self) -> Result<&'static str, ErrorStack> {
|
pub fn short_name(&self) -> Result<&'static str, ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let nameptr = cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char)?;
|
let nameptr = cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char)?;
|
||||||
str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).map_err(ErrorStack::internal_error)
|
CStr::from_ptr(nameptr)
|
||||||
|
.to_str()
|
||||||
|
.map_err(ErrorStack::internal_error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ mod test {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
builder.set_subject_name(&name).unwrap();
|
builder.set_subject_name(&name).unwrap();
|
||||||
builder.set_issuer_name(&name).unwrap();
|
builder.set_issuer_name(&name).unwrap();
|
||||||
builder.append_extension(key_usage).unwrap();
|
builder.append_extension(&key_usage).unwrap();
|
||||||
builder.set_pubkey(&pkey).unwrap();
|
builder.set_pubkey(&pkey).unwrap();
|
||||||
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
||||||
let cert = builder.build();
|
let cert = builder.build();
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ impl SslContextBuilder {
|
||||||
let finish = fut_result.or(Err(SelectCertError::ERROR))?;
|
let finish = fut_result.or(Err(SelectCertError::ERROR))?;
|
||||||
|
|
||||||
finish(client_hello).or(Err(SelectCertError::ERROR))
|
finish(client_hello).or(Err(SelectCertError::ERROR))
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures a custom private key method on the context.
|
/// Configures a custom private key method on the context.
|
||||||
|
|
@ -144,7 +144,7 @@ impl SslContextBuilder {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.set_get_session_callback(async_callback)
|
self.set_get_session_callback(async_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures certificate verification.
|
/// Configures certificate verification.
|
||||||
|
|
@ -167,7 +167,7 @@ impl SslContextBuilder {
|
||||||
where
|
where
|
||||||
F: Fn(&mut SslRef) -> Result<BoxCustomVerifyFuture, SslAlert> + Send + Sync + 'static,
|
F: Fn(&mut SslRef) -> Result<BoxCustomVerifyFuture, SslAlert> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
self.set_custom_verify_callback(mode, async_custom_verify_callback(callback))
|
self.set_custom_verify_callback(mode, async_custom_verify_callback(callback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,7 +176,7 @@ impl SslRef {
|
||||||
where
|
where
|
||||||
F: Fn(&mut SslRef) -> Result<BoxCustomVerifyFuture, SslAlert> + Send + Sync + 'static,
|
F: Fn(&mut SslRef) -> Result<BoxCustomVerifyFuture, SslAlert> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
self.set_custom_verify_callback(mode, async_custom_verify_callback(callback))
|
self.set_custom_verify_callback(mode, async_custom_verify_callback(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the task waker to be used in async callbacks installed on this `Ssl`.
|
/// Sets the task waker to be used in async callbacks installed on this `Ssl`.
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,15 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::error::ErrorStack;
|
use crate::error::ErrorStack;
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
use crate::hmac::HmacCtxRef;
|
||||||
|
use crate::ssl::TicketKeyCallbackResult;
|
||||||
|
use crate::symm::CipherCtxRef;
|
||||||
use crate::x509::{X509StoreContext, X509StoreContextRef};
|
use crate::x509::{X509StoreContext, X509StoreContextRef};
|
||||||
use foreign_types::ForeignType;
|
use foreign_types::ForeignType;
|
||||||
use foreign_types::ForeignTypeRef;
|
use foreign_types::ForeignTypeRef;
|
||||||
use libc::c_char;
|
use libc::{c_char, c_int, c_uchar, c_uint, c_void};
|
||||||
use libc::{c_int, c_uchar, c_uint, c_void};
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
use std::mem::{self, MaybeUninit};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
@ -269,6 +272,68 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn to_uninit<'a, T: 'a>(ptr: *mut T) -> &'a mut MaybeUninit<T> {
|
||||||
|
assert!(!ptr.is_null());
|
||||||
|
unsafe { &mut *ptr.cast::<MaybeUninit<T>>() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe extern "C" fn raw_ticket_key<F>(
|
||||||
|
ssl: *mut ffi::SSL,
|
||||||
|
key_name: *mut u8,
|
||||||
|
iv: *mut u8,
|
||||||
|
evp_ctx: *mut ffi::EVP_CIPHER_CTX,
|
||||||
|
hmac_ctx: *mut ffi::HMAC_CTX,
|
||||||
|
encrypt: c_int,
|
||||||
|
) -> c_int
|
||||||
|
where
|
||||||
|
F: Fn(
|
||||||
|
&SslRef,
|
||||||
|
&mut [u8; 16],
|
||||||
|
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
&mut CipherCtxRef,
|
||||||
|
&mut HmacCtxRef,
|
||||||
|
bool,
|
||||||
|
) -> TicketKeyCallbackResult
|
||||||
|
+ 'static
|
||||||
|
+ Sync
|
||||||
|
+ Send,
|
||||||
|
{
|
||||||
|
// SAFETY: boring provides valid inputs.
|
||||||
|
let ssl = unsafe { SslRef::from_ptr_mut(ssl) };
|
||||||
|
|
||||||
|
let ssl_context = ssl.ssl_context().to_owned();
|
||||||
|
let callback = ssl_context
|
||||||
|
.ex_data::<F>(SslContext::cached_ex_index::<F>())
|
||||||
|
.expect("expected session resumption callback");
|
||||||
|
|
||||||
|
// SAFETY: the callback guarantees that key_name is 16 bytes
|
||||||
|
let key_name =
|
||||||
|
unsafe { to_uninit(key_name.cast::<[u8; ffi::SSL_TICKET_KEY_NAME_LEN as usize]>()) };
|
||||||
|
|
||||||
|
// SAFETY: the callback provides 16 bytes iv
|
||||||
|
//
|
||||||
|
// https://github.com/google/boringssl/blob/main/ssl/ssl_session.cc#L331
|
||||||
|
let iv = unsafe { to_uninit(iv.cast::<[u8; ffi::EVP_MAX_IV_LENGTH as usize]>()) };
|
||||||
|
|
||||||
|
// When encrypting a new ticket, encrypt will be one.
|
||||||
|
let encrypt = encrypt == 1;
|
||||||
|
|
||||||
|
// Zero-initialize the key_name and iv, since the application is expected to populate these
|
||||||
|
// fields in the encrypt mode.
|
||||||
|
if encrypt {
|
||||||
|
*key_name = MaybeUninit::zeroed();
|
||||||
|
*iv = MaybeUninit::zeroed();
|
||||||
|
}
|
||||||
|
let key_name = unsafe { key_name.assume_init_mut() };
|
||||||
|
let iv = unsafe { iv.assume_init_mut() };
|
||||||
|
|
||||||
|
// The EVP_CIPHER_CTX and HMAC_CTX are owned by boringSSL.
|
||||||
|
let evp_ctx = unsafe { CipherCtxRef::from_ptr_mut(evp_ctx) };
|
||||||
|
let hmac_ctx = unsafe { HmacCtxRef::from_ptr_mut(hmac_ctx) };
|
||||||
|
|
||||||
|
callback(ssl, key_name, iv, evp_ctx, hmac_ctx, encrypt).into()
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) unsafe extern "C" fn raw_alpn_select<F>(
|
pub(super) unsafe extern "C" fn raw_alpn_select<F>(
|
||||||
ssl: *mut ffi::SSL,
|
ssl: *mut ffi::SSL,
|
||||||
out: *mut *const c_uchar,
|
out: *mut *const c_uchar,
|
||||||
|
|
@ -399,7 +464,7 @@ pub(super) unsafe extern "C" fn raw_remove_session<F>(
|
||||||
.ex_data(SslContext::cached_ex_index::<F>())
|
.ex_data(SslContext::cached_ex_index::<F>())
|
||||||
.expect("BUG: remove session callback missing");
|
.expect("BUG: remove session callback missing");
|
||||||
|
|
||||||
callback(ctx, session)
|
callback(ctx, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
type DataPtr = *const c_uchar;
|
type DataPtr = *const c_uchar;
|
||||||
|
|
@ -451,14 +516,14 @@ where
|
||||||
{
|
{
|
||||||
// SAFETY: boring provides valid inputs.
|
// SAFETY: boring provides valid inputs.
|
||||||
let ssl = unsafe { SslRef::from_ptr(ssl as *mut _) };
|
let ssl = unsafe { SslRef::from_ptr(ssl as *mut _) };
|
||||||
let line = unsafe { str::from_utf8_unchecked(CStr::from_ptr(line).to_bytes()) };
|
let line = unsafe { CStr::from_ptr(line).to_string_lossy() };
|
||||||
|
|
||||||
let callback = ssl
|
let callback = ssl
|
||||||
.ssl_context()
|
.ssl_context()
|
||||||
.ex_data(SslContext::cached_ex_index::<F>())
|
.ex_data(SslContext::cached_ex_index::<F>())
|
||||||
.expect("BUG: get session callback missing");
|
.expect("BUG: get session callback missing");
|
||||||
|
|
||||||
callback(ssl, line);
|
callback(ssl, &line);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe extern "C" fn raw_sign<M>(
|
pub(super) unsafe extern "C" fn raw_sign<M>(
|
||||||
|
|
@ -702,14 +767,10 @@ impl<'a> CryptoBufferBuilder<'a> {
|
||||||
let buffer_capacity = unsafe { ffi::CRYPTO_BUFFER_len(self.buffer) };
|
let buffer_capacity = unsafe { ffi::CRYPTO_BUFFER_len(self.buffer) };
|
||||||
if self.cursor.position() != buffer_capacity as u64 {
|
if self.cursor.position() != buffer_capacity as u64 {
|
||||||
// Make sure all bytes in buffer initialized as required by Boring SSL.
|
// Make sure all bytes in buffer initialized as required by Boring SSL.
|
||||||
return Err(ErrorStack::get());
|
return Err(ErrorStack::internal_error_str("invalid len"));
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
let mut result = ptr::null_mut();
|
|
||||||
ptr::swap(&mut self.buffer, &mut result);
|
|
||||||
std::mem::forget(self);
|
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
|
// Drop is no-op if the buffer is null
|
||||||
|
Ok(mem::replace(&mut self.buffer, ptr::null_mut()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ use crate::dh::DhRef;
|
||||||
use crate::ec::EcKeyRef;
|
use crate::ec::EcKeyRef;
|
||||||
use crate::error::ErrorStack;
|
use crate::error::ErrorStack;
|
||||||
use crate::ex_data::Index;
|
use crate::ex_data::Index;
|
||||||
|
use crate::hmac::HmacCtxRef;
|
||||||
use crate::nid::Nid;
|
use crate::nid::Nid;
|
||||||
use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
|
use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
|
||||||
use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
|
use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
|
||||||
|
|
@ -90,6 +91,7 @@ use crate::ssl::callbacks::*;
|
||||||
use crate::ssl::ech::SslEchKeys;
|
use crate::ssl::ech::SslEchKeys;
|
||||||
use crate::ssl::error::InnerError;
|
use crate::ssl::error::InnerError;
|
||||||
use crate::stack::{Stack, StackRef, Stackable};
|
use crate::stack::{Stack, StackRef, Stackable};
|
||||||
|
use crate::symm::CipherCtxRef;
|
||||||
use crate::x509::store::{X509Store, X509StoreBuilder, X509StoreBuilderRef, X509StoreRef};
|
use crate::x509::store::{X509Store, X509StoreBuilder, X509StoreBuilderRef, X509StoreRef};
|
||||||
use crate::x509::verify::X509VerifyParamRef;
|
use crate::x509::verify::X509VerifyParamRef;
|
||||||
use crate::x509::{
|
use crate::x509::{
|
||||||
|
|
@ -114,7 +116,6 @@ mod async_callbacks;
|
||||||
mod bio;
|
mod bio;
|
||||||
mod callbacks;
|
mod callbacks;
|
||||||
mod connector;
|
mod connector;
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
mod ech;
|
mod ech;
|
||||||
mod error;
|
mod error;
|
||||||
mod mut_only;
|
mod mut_only;
|
||||||
|
|
@ -697,131 +698,13 @@ impl From<u16> for SslSignatureAlgorithm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Numeric identifier of a TLS curve.
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub struct SslCurveNid(c_int);
|
|
||||||
|
|
||||||
/// A TLS Curve.
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub struct SslCurve(c_int);
|
|
||||||
|
|
||||||
impl SslCurve {
|
|
||||||
pub const SECP224R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP224R1 as _);
|
|
||||||
|
|
||||||
pub const SECP256R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP256R1 as _);
|
|
||||||
|
|
||||||
pub const SECP384R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP384R1 as _);
|
|
||||||
|
|
||||||
pub const SECP521R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP521R1 as _);
|
|
||||||
|
|
||||||
pub const X25519: SslCurve = SslCurve(ffi::SSL_CURVE_X25519 as _);
|
|
||||||
|
|
||||||
pub const FFDHE2048: SslCurve = SslCurve(ffi::SSL_CURVE_DHE2048 as _);
|
|
||||||
|
|
||||||
pub const FFDHE3072: SslCurve = SslCurve(ffi::SSL_CURVE_DHE3072 as _);
|
|
||||||
|
|
||||||
#[cfg(feature = "pq-experimental")]
|
|
||||||
#[cfg(not(any(feature = "fips", feature = "fips-precompiled")))]
|
|
||||||
pub const X25519_KYBER768_DRAFT00: SslCurve =
|
|
||||||
SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 as _);
|
|
||||||
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
pub const X25519_KYBER768_DRAFT00_OLD: SslCurve =
|
|
||||||
SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD as _);
|
|
||||||
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
pub const X25519_KYBER512_DRAFT00: SslCurve =
|
|
||||||
SslCurve(ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 as _);
|
|
||||||
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_P256_KYBER768_DRAFT00 as _);
|
|
||||||
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
pub const X25519_MLKEM768: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_MLKEM768 as _);
|
|
||||||
|
|
||||||
/// Returns the curve name
|
|
||||||
#[corresponds(SSL_get_curve_name)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn name(&self) -> Option<&'static str> {
|
|
||||||
unsafe {
|
|
||||||
let ptr = ffi::SSL_get_curve_name(self.0 as u16);
|
|
||||||
if ptr.is_null() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
CStr::from_ptr(ptr).to_str().ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to allow dead_code here because `SslRef::set_curves` is conditionally compiled
|
|
||||||
// against the absence of the `kx-safe-default` feature and thus this function is never used.
|
|
||||||
//
|
|
||||||
// **NOTE**: This function only exists because the version of boringssl we currently use does
|
|
||||||
// not expose SSL_CTX_set1_group_ids. Because `SslRef::curve()` returns the public SSL_CURVE id
|
|
||||||
// as opposed to the internal NID, but `SslContextBuilder::set_curves()` requires the internal
|
|
||||||
// NID, we need this mapping in place to avoid breaking changes to the public API. Once the
|
|
||||||
// underlying boringssl version is upgraded, this should be removed in favor of the new
|
|
||||||
// SSL_CTX_set1_group_ids API.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn nid(&self) -> Option<SslCurveNid> {
|
|
||||||
match self.0 {
|
|
||||||
ffi::SSL_CURVE_SECP224R1 => Some(ffi::NID_secp224r1),
|
|
||||||
ffi::SSL_CURVE_SECP256R1 => Some(ffi::NID_X9_62_prime256v1),
|
|
||||||
ffi::SSL_CURVE_SECP384R1 => Some(ffi::NID_secp384r1),
|
|
||||||
ffi::SSL_CURVE_SECP521R1 => Some(ffi::NID_secp521r1),
|
|
||||||
ffi::SSL_CURVE_X25519 => Some(ffi::NID_X25519),
|
|
||||||
#[cfg(not(any(feature = "fips", feature = "fips-precompiled")))]
|
|
||||||
ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00),
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old),
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00),
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
ffi::SSL_CURVE_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00),
|
|
||||||
#[cfg(all(
|
|
||||||
not(any(feature = "fips", feature = "fips-precompiled")),
|
|
||||||
feature = "pq-experimental"
|
|
||||||
))]
|
|
||||||
ffi::SSL_CURVE_X25519_MLKEM768 => Some(ffi::NID_X25519MLKEM768),
|
|
||||||
ffi::SSL_CURVE_DHE2048 => Some(ffi::NID_ffdhe2048),
|
|
||||||
ffi::SSL_CURVE_DHE3072 => Some(ffi::NID_ffdhe3072),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
.map(SslCurveNid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A compliance policy.
|
/// A compliance policy.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
pub struct CompliancePolicy(ffi::ssl_compliance_policy_t);
|
pub struct CompliancePolicy(ffi::ssl_compliance_policy_t);
|
||||||
|
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
impl CompliancePolicy {
|
impl CompliancePolicy {
|
||||||
/// Does nothing, however setting this does not undo other policies, so trying to set this is an error.
|
/// Does nothing, however setting this does not undo other policies, so trying to set this is an error.
|
||||||
|
#[cfg(not(feature = "legacy-compat-deprecated"))]
|
||||||
pub const NONE: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_none);
|
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.
|
/// Configures a TLS connection to try and be compliant with NIST requirements, but does not guarantee success.
|
||||||
|
|
@ -831,6 +714,7 @@ impl CompliancePolicy {
|
||||||
|
|
||||||
/// Partially configures a TLS connection to be compliant with WPA3. Callers must enforce certificate chain requirements themselves.
|
/// 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.
|
/// Use of this policy is less secure than the default and not recommended.
|
||||||
|
#[cfg(not(feature = "legacy-compat-deprecated"))]
|
||||||
pub const WPA3_192_202304: Self =
|
pub const WPA3_192_202304: Self =
|
||||||
Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_wpa3_192_202304);
|
Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_wpa3_192_202304);
|
||||||
}
|
}
|
||||||
|
|
@ -925,6 +809,53 @@ pub enum SslInfoCallbackValue {
|
||||||
Alert(SslInfoCallbackAlert),
|
Alert(SslInfoCallbackAlert),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ticket key callback status.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum TicketKeyCallbackResult {
|
||||||
|
/// Abort the handshake.
|
||||||
|
Error,
|
||||||
|
|
||||||
|
/// Continue with a full handshake.
|
||||||
|
///
|
||||||
|
/// When in decryption mode, this indicates that the peer supplied session ticket was not
|
||||||
|
/// recognized. When in encryption mode, this instructs boring to not send a session ticket.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// This is a decryption specific status code when using the submoduled BoringSSL.
|
||||||
|
Noop,
|
||||||
|
|
||||||
|
/// Resumption callback was successful.
|
||||||
|
///
|
||||||
|
/// When in decryption mode, attempt an abbreviated handshake via session resumption. When in
|
||||||
|
/// encryption mode, provide a new ticket to the client.
|
||||||
|
Success,
|
||||||
|
|
||||||
|
/// Resumption callback was successful. Attempt an abbreviated handshake, and additionally
|
||||||
|
/// provide new session tickets to the peer.
|
||||||
|
///
|
||||||
|
/// Session resumption short-circuits some security checks of a full-handshake, in exchange for
|
||||||
|
/// potential performance gains. For this reason, a session ticket should only be valid for a
|
||||||
|
/// limited time. Providing the peer with renewed session tickets allows them to continue
|
||||||
|
/// session resumption with the new tickets.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// This is a decryption specific status code.
|
||||||
|
DecryptSuccessRenew,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TicketKeyCallbackResult> for c_int {
|
||||||
|
fn from(value: TicketKeyCallbackResult) -> Self {
|
||||||
|
match value {
|
||||||
|
TicketKeyCallbackResult::Error => -1,
|
||||||
|
TicketKeyCallbackResult::Noop => 0,
|
||||||
|
TicketKeyCallbackResult::Success => 1,
|
||||||
|
TicketKeyCallbackResult::DecryptSuccessRenew => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Hash, Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
#[derive(Hash, Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
||||||
pub struct SslInfoCallbackAlert(c_int);
|
pub struct SslInfoCallbackAlert(c_int);
|
||||||
|
|
||||||
|
|
@ -966,7 +897,6 @@ impl SslContextBuilder {
|
||||||
unsafe {
|
unsafe {
|
||||||
init();
|
init();
|
||||||
let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?;
|
let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?;
|
||||||
|
|
||||||
Ok(SslContextBuilder::from_ptr(ctx))
|
Ok(SslContextBuilder::from_ptr(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -977,9 +907,10 @@ impl SslContextBuilder {
|
||||||
///
|
///
|
||||||
/// The caller must ensure that the pointer is valid and uniquely owned by the builder.
|
/// The caller must ensure that the pointer is valid and uniquely owned by the builder.
|
||||||
pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder {
|
pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder {
|
||||||
|
let ctx = SslContext::from_ptr(ctx);
|
||||||
SslContextBuilder {
|
SslContextBuilder {
|
||||||
ctx: SslContext::from_ptr(ctx),
|
|
||||||
has_shared_cert_store: false,
|
has_shared_cert_store: false,
|
||||||
|
ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1125,6 +1056,49 @@ impl SslContextBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configures a custom session ticket key callback for session resumption.
|
||||||
|
///
|
||||||
|
/// Session Resumption uses the security context (aka. session tickets) of a previous
|
||||||
|
/// connection to establish a new connection via an abbreviated handshake. Skipping portions of
|
||||||
|
/// a handshake can potentially yield performance gains.
|
||||||
|
///
|
||||||
|
/// An attacker that compromises a server's session ticket key can impersonate the server and,
|
||||||
|
/// prior to TLS 1.3, retroactively decrypt all application traffic from sessions using that
|
||||||
|
/// ticket key. Thus ticket keys must be regularly rotated for forward secrecy.
|
||||||
|
///
|
||||||
|
/// CipherCtx and HmacCtx are guaranteed to be initialized.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This method panics if this `Ssl` is associated with a RPK context.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The application is responsible for correctly setting the key_name, iv, encryption context
|
||||||
|
/// and hmac context. See the [`SSL_CTX_set_tlsext_ticket_key_cb`] docs for additional info.
|
||||||
|
///
|
||||||
|
/// [`SSL_CTX_set_tlsext_ticket_key_cb`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_tlsext_ticket_key_cb
|
||||||
|
#[corresponds(SSL_CTX_set_tlsext_ticket_key_cb)]
|
||||||
|
pub unsafe fn set_ticket_key_callback<F>(&mut self, callback: F)
|
||||||
|
where
|
||||||
|
F: Fn(
|
||||||
|
&SslRef,
|
||||||
|
&mut [u8; 16],
|
||||||
|
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
&mut CipherCtxRef,
|
||||||
|
&mut HmacCtxRef,
|
||||||
|
bool,
|
||||||
|
) -> TicketKeyCallbackResult
|
||||||
|
+ 'static
|
||||||
|
+ Sync
|
||||||
|
+ Send,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
|
||||||
|
ffi::SSL_CTX_set_tlsext_ticket_key_cb(self.as_ptr(), Some(raw_ticket_key::<F>))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the certificate verification depth.
|
/// Sets the certificate verification depth.
|
||||||
///
|
///
|
||||||
/// If the peer's certificate chain is longer than this value, verification will fail.
|
/// If the peer's certificate chain is longer than this value, verification will fail.
|
||||||
|
|
@ -1493,7 +1467,10 @@ impl SslContextBuilder {
|
||||||
#[corresponds(SSL_CTX_set_alpn_protos)]
|
#[corresponds(SSL_CTX_set_alpn_protos)]
|
||||||
pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
|
pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
#[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))]
|
#[cfg_attr(
|
||||||
|
not(feature = "legacy-compat-deprecated"),
|
||||||
|
allow(clippy::unnecessary_cast)
|
||||||
|
)]
|
||||||
{
|
{
|
||||||
assert!(protocols.len() <= ProtosLen::MAX as usize);
|
assert!(protocols.len() <= ProtosLen::MAX as usize);
|
||||||
}
|
}
|
||||||
|
|
@ -1719,7 +1696,7 @@ impl SslContextBuilder {
|
||||||
+ Sync
|
+ Sync
|
||||||
+ Send,
|
+ Send,
|
||||||
{
|
{
|
||||||
self.set_psk_client_callback(callback)
|
self.set_psk_client_callback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server.
|
/// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server.
|
||||||
|
|
@ -1950,7 +1927,6 @@ impl SslContextBuilder {
|
||||||
|
|
||||||
/// Sets the indices of the extensions to be permuted.
|
/// Sets the indices of the extensions to be permuted.
|
||||||
#[corresponds(SSL_CTX_set_extension_order)]
|
#[corresponds(SSL_CTX_set_extension_order)]
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
pub fn set_extension_permutation(
|
pub fn set_extension_permutation(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &[ExtensionType],
|
indices: &[ExtensionType],
|
||||||
|
|
@ -1966,12 +1942,7 @@ impl SslContextBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures whether ClientHello extensions should be permuted.
|
/// Configures whether ClientHello extensions should be permuted.
|
||||||
///
|
|
||||||
/// Note: This is gated to non-fips because the fips feature builds with a separate
|
|
||||||
/// version of BoringSSL which doesn't yet include these APIs.
|
|
||||||
/// Once the submoduled fips commit is upgraded, these gates can be removed.
|
|
||||||
#[corresponds(SSL_CTX_set_permute_extensions)]
|
#[corresponds(SSL_CTX_set_permute_extensions)]
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
pub fn set_permute_extensions(&mut self, enabled: bool) {
|
pub fn set_permute_extensions(&mut self, enabled: bool) {
|
||||||
unsafe { ffi::SSL_CTX_set_permute_extensions(self.as_ptr(), enabled as _) }
|
unsafe { ffi::SSL_CTX_set_permute_extensions(self.as_ptr(), enabled as _) }
|
||||||
}
|
}
|
||||||
|
|
@ -2005,11 +1976,6 @@ impl SslContextBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the context's supported curves.
|
/// Sets the context's supported curves.
|
||||||
//
|
|
||||||
// If the "kx-*" flags are used to set key exchange preference, then don't allow the user to
|
|
||||||
// set them here. This ensures we don't override the user's preference without telling them:
|
|
||||||
// when the flags are used, the preferences are set just before connecting or accepting.
|
|
||||||
#[cfg(not(feature = "kx-safe-default"))]
|
|
||||||
#[corresponds(SSL_CTX_set1_curves_list)]
|
#[corresponds(SSL_CTX_set1_curves_list)]
|
||||||
pub fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> {
|
pub fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> {
|
||||||
let curves = CString::new(curves).map_err(ErrorStack::internal_error)?;
|
let curves = CString::new(curves).map_err(ErrorStack::internal_error)?;
|
||||||
|
|
@ -2022,34 +1988,10 @@ impl SslContextBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the context's supported curves.
|
|
||||||
//
|
|
||||||
// If the "kx-*" flags are used to set key exchange preference, then don't allow the user to
|
|
||||||
// set them here. This ensures we don't override the user's preference without telling them:
|
|
||||||
// when the flags are used, the preferences are set just before connecting or accepting.
|
|
||||||
#[corresponds(SSL_CTX_set1_curves)]
|
|
||||||
#[cfg(not(feature = "kx-safe-default"))]
|
|
||||||
pub fn set_curves(&mut self, curves: &[SslCurve]) -> Result<(), ErrorStack> {
|
|
||||||
let curves: Vec<i32> = curves
|
|
||||||
.iter()
|
|
||||||
.filter_map(|curve| curve.nid().map(|nid| nid.0))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
cvt_0i(ffi::SSL_CTX_set1_curves(
|
|
||||||
self.as_ptr(),
|
|
||||||
curves.as_ptr() as *const _,
|
|
||||||
curves.len(),
|
|
||||||
))
|
|
||||||
.map(|_| ())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the context's compliance policy.
|
/// Sets the context's compliance policy.
|
||||||
///
|
///
|
||||||
/// This feature isn't available in the certified version of BoringSSL.
|
/// This feature isn't available in the certified version of BoringSSL.
|
||||||
#[corresponds(SSL_CTX_set_compliance_policy)]
|
#[corresponds(SSL_CTX_set_compliance_policy)]
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> {
|
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(|_| ()) }
|
unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) }
|
||||||
}
|
}
|
||||||
|
|
@ -2070,7 +2012,6 @@ impl SslContextBuilder {
|
||||||
/// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function
|
/// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function
|
||||||
/// is safe to call even after the `SSL_CTX` has been associated with connections on various
|
/// is safe to call even after the `SSL_CTX` has been associated with connections on various
|
||||||
/// threads.
|
/// threads.
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
#[corresponds(SSL_CTX_set1_ech_keys)]
|
#[corresponds(SSL_CTX_set1_ech_keys)]
|
||||||
pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> {
|
pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> {
|
||||||
unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) }
|
unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) }
|
||||||
|
|
@ -2323,7 +2264,6 @@ impl SslContextRef {
|
||||||
/// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function
|
/// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function
|
||||||
/// is safe to call even after the `SSL_CTX` has been associated with connections on various
|
/// is safe to call even after the `SSL_CTX` has been associated with connections on various
|
||||||
/// threads.
|
/// threads.
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
#[corresponds(SSL_CTX_set1_ech_keys)]
|
#[corresponds(SSL_CTX_set1_ech_keys)]
|
||||||
pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> {
|
pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> {
|
||||||
unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) }
|
unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) }
|
||||||
|
|
@ -2337,9 +2277,9 @@ impl SslContextRef {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GetSessionPendingError;
|
pub struct GetSessionPendingError;
|
||||||
|
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
#[cfg(not(feature = "legacy-compat-deprecated"))]
|
||||||
type ProtosLen = usize;
|
type ProtosLen = usize;
|
||||||
#[cfg(feature = "fips-compat")]
|
#[cfg(feature = "legacy-compat-deprecated")]
|
||||||
type ProtosLen = libc::c_uint;
|
type ProtosLen = libc::c_uint;
|
||||||
|
|
||||||
/// Information about the state of a cipher.
|
/// Information about the state of a cipher.
|
||||||
|
|
@ -2511,7 +2451,7 @@ impl SslCipherRef {
|
||||||
CStr::from_ptr(ptr as *const _)
|
CStr::from_ptr(ptr as *const _)
|
||||||
};
|
};
|
||||||
|
|
||||||
str::from_utf8(version.to_bytes()).unwrap()
|
version.to_str().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of bits used for the cipher.
|
/// Returns the number of bits used for the cipher.
|
||||||
|
|
@ -2537,7 +2477,7 @@ impl SslCipherRef {
|
||||||
// SSL_CIPHER_description requires a buffer of at least 128 bytes.
|
// SSL_CIPHER_description requires a buffer of at least 128 bytes.
|
||||||
let mut buf = [0; 128];
|
let mut buf = [0; 128];
|
||||||
let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
|
let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
|
||||||
String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap()
|
CStr::from_ptr(ptr.cast()).to_string_lossy().into_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2725,32 +2665,13 @@ impl Ssl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `Ssl`.
|
|
||||||
///
|
|
||||||
// FIXME should take &SslContextRef
|
|
||||||
#[corresponds(SSL_new)]
|
|
||||||
pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
|
|
||||||
unsafe {
|
|
||||||
let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
|
|
||||||
let mut ssl = Ssl::from_ptr(ptr);
|
|
||||||
ssl.set_ex_data(*SESSION_CTX_INDEX, ctx.clone());
|
|
||||||
|
|
||||||
Ok(ssl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new [`Ssl`].
|
/// Creates a new [`Ssl`].
|
||||||
///
|
|
||||||
/// This function does the same as [`Self:new`] except that it takes &[SslContextRef].
|
|
||||||
// Both functions exist for backward compatibility (no breaking API).
|
|
||||||
#[corresponds(SSL_new)]
|
#[corresponds(SSL_new)]
|
||||||
pub fn new_from_ref(ctx: &SslContextRef) -> Result<Ssl, ErrorStack> {
|
pub fn new(ctx: &SslContextRef) -> Result<Ssl, ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
|
let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
|
||||||
let mut ssl = Ssl::from_ptr(ptr);
|
let mut ssl = Ssl::from_ptr(ptr);
|
||||||
SSL_CTX_up_ref(ctx.as_ptr());
|
ssl.set_ex_data(*SESSION_CTX_INDEX, ctx.to_owned());
|
||||||
let ctx_owned = SslContext::from_ptr(ctx.as_ptr());
|
|
||||||
ssl.set_ex_data(*SESSION_CTX_INDEX, ctx_owned);
|
|
||||||
|
|
||||||
Ok(ssl)
|
Ok(ssl)
|
||||||
}
|
}
|
||||||
|
|
@ -2875,63 +2796,31 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the ongoing session's supported groups by their named identifiers
|
/// Returns the curve ID (aka group ID) used for this `SslRef`.
|
||||||
/// (formerly referred to as curves).
|
|
||||||
#[corresponds(SSL_set1_groups)]
|
|
||||||
pub fn set_group_nids(&mut self, group_nids: &[SslCurveNid]) -> Result<(), ErrorStack> {
|
|
||||||
unsafe {
|
|
||||||
cvt_0i(ffi::SSL_set1_curves(
|
|
||||||
self.as_ptr(),
|
|
||||||
group_nids.as_ptr() as *const _,
|
|
||||||
group_nids.len(),
|
|
||||||
))
|
|
||||||
.map(|_| ())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "kx-safe-default")]
|
|
||||||
fn client_set_default_curves_list(&mut self) {
|
|
||||||
let curves = if cfg!(feature = "kx-client-pq-preferred") {
|
|
||||||
if cfg!(feature = "kx-client-nist-required") {
|
|
||||||
"P256Kyber768Draft00:P-256:P-384:P-521"
|
|
||||||
} else {
|
|
||||||
"X25519MLKEM768:X25519Kyber768Draft00:X25519:P256Kyber768Draft00:P-256:P-384:P-521"
|
|
||||||
}
|
|
||||||
} else if cfg!(feature = "kx-client-pq-supported") {
|
|
||||||
if cfg!(feature = "kx-client-nist-required") {
|
|
||||||
"P-256:P-384:P-521:P256Kyber768Draft00"
|
|
||||||
} else {
|
|
||||||
"X25519:P-256:P-384:P-521:X25519MLKEM768:X25519Kyber768Draft00:P256Kyber768Draft00"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if cfg!(feature = "kx-client-nist-required") {
|
|
||||||
"P-256:P-384:P-521"
|
|
||||||
} else {
|
|
||||||
"X25519:P-256:P-384:P-521"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.set_curves_list(curves)
|
|
||||||
.expect("invalid default client curves list");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "kx-safe-default")]
|
|
||||||
fn server_set_default_curves_list(&mut self) {
|
|
||||||
self.set_curves_list(
|
|
||||||
"X25519MLKEM768:X25519Kyber768Draft00:P256Kyber768Draft00:X25519:P-256:P-384",
|
|
||||||
)
|
|
||||||
.expect("invalid default server curves list");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the [`SslCurve`] used for this `SslRef`.
|
|
||||||
#[corresponds(SSL_get_curve_id)]
|
#[corresponds(SSL_get_curve_id)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn curve(&self) -> Option<SslCurve> {
|
pub fn curve(&self) -> Option<u16> {
|
||||||
let curve_id = unsafe { ffi::SSL_get_curve_id(self.as_ptr()) };
|
let curve_id = unsafe { ffi::SSL_get_curve_id(self.as_ptr()) };
|
||||||
if curve_id == 0 {
|
if curve_id == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(SslCurve(curve_id.into()))
|
Some(curve_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the curve name used for this `SslRef`.
|
||||||
|
#[corresponds(SSL_get_curve_name)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn curve_name(&self) -> Option<&'static str> {
|
||||||
|
let curve_id = self.curve()?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = ffi::SSL_get_curve_name(curve_id);
|
||||||
|
if ptr.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
CStr::from_ptr(ptr).to_str().ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an `ErrorCode` value for the most recent operation on this `SslRef`.
|
/// Returns an `ErrorCode` value for the most recent operation on this `SslRef`.
|
||||||
|
|
@ -3047,11 +2936,6 @@ impl SslRef {
|
||||||
|
|
||||||
/// Configures whether ClientHello extensions should be permuted.
|
/// Configures whether ClientHello extensions should be permuted.
|
||||||
#[corresponds(SSL_set_permute_extensions)]
|
#[corresponds(SSL_set_permute_extensions)]
|
||||||
///
|
|
||||||
/// Note: This is gated to non-fips because the fips feature builds with a separate
|
|
||||||
/// version of BoringSSL which doesn't yet include these APIs.
|
|
||||||
/// Once the submoduled fips commit is upgraded, these gates can be removed.
|
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
pub fn set_permute_extensions(&mut self, enabled: bool) {
|
pub fn set_permute_extensions(&mut self, enabled: bool) {
|
||||||
unsafe { ffi::SSL_set_permute_extensions(self.as_ptr(), enabled as _) }
|
unsafe { ffi::SSL_set_permute_extensions(self.as_ptr(), enabled as _) }
|
||||||
}
|
}
|
||||||
|
|
@ -3062,7 +2946,10 @@ impl SslRef {
|
||||||
#[corresponds(SSL_set_alpn_protos)]
|
#[corresponds(SSL_set_alpn_protos)]
|
||||||
pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
|
pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
#[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))]
|
#[cfg_attr(
|
||||||
|
not(feature = "legacy-compat-deprecated"),
|
||||||
|
allow(clippy::unnecessary_cast)
|
||||||
|
)]
|
||||||
{
|
{
|
||||||
assert!(protocols.len() <= ProtosLen::MAX as usize);
|
assert!(protocols.len() <= ProtosLen::MAX as usize);
|
||||||
}
|
}
|
||||||
|
|
@ -3106,6 +2993,8 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a short string describing the state of the session.
|
/// Returns a short string describing the state of the session.
|
||||||
|
///
|
||||||
|
/// Returns empty string if the state wasn't valid UTF-8.
|
||||||
#[corresponds(SSL_state_string)]
|
#[corresponds(SSL_state_string)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn state_string(&self) -> &'static str {
|
pub fn state_string(&self) -> &'static str {
|
||||||
|
|
@ -3114,10 +3003,12 @@ impl SslRef {
|
||||||
CStr::from_ptr(ptr as *const _)
|
CStr::from_ptr(ptr as *const _)
|
||||||
};
|
};
|
||||||
|
|
||||||
str::from_utf8(state.to_bytes()).unwrap()
|
state.to_str().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a longer string describing the state of the session.
|
/// Returns a longer string describing the state of the session.
|
||||||
|
///
|
||||||
|
/// Returns empty string if the state wasn't valid UTF-8.
|
||||||
#[corresponds(SSL_state_string_long)]
|
#[corresponds(SSL_state_string_long)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn state_string_long(&self) -> &'static str {
|
pub fn state_string_long(&self) -> &'static str {
|
||||||
|
|
@ -3126,7 +3017,7 @@ impl SslRef {
|
||||||
CStr::from_ptr(ptr as *const _)
|
CStr::from_ptr(ptr as *const _)
|
||||||
};
|
};
|
||||||
|
|
||||||
str::from_utf8(state.to_bytes()).unwrap()
|
state.to_str().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the host name to be sent to the server for Server Name Indication (SNI).
|
/// Sets the host name to be sent to the server for Server Name Indication (SNI).
|
||||||
|
|
@ -3220,6 +3111,8 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a string describing the protocol version of the session.
|
/// Returns a string describing the protocol version of the session.
|
||||||
|
///
|
||||||
|
/// This may panic if the string isn't valid UTF-8 for some reason. Use [`Self::version2`] instead.
|
||||||
#[corresponds(SSL_get_version)]
|
#[corresponds(SSL_get_version)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn version_str(&self) -> &'static str {
|
pub fn version_str(&self) -> &'static str {
|
||||||
|
|
@ -3228,7 +3121,7 @@ impl SslRef {
|
||||||
CStr::from_ptr(ptr as *const _)
|
CStr::from_ptr(ptr as *const _)
|
||||||
};
|
};
|
||||||
|
|
||||||
str::from_utf8(version.to_bytes()).unwrap()
|
version.to_str().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the minimum supported protocol version.
|
/// Sets the minimum supported protocol version.
|
||||||
|
|
@ -3734,7 +3627,6 @@ impl SslRef {
|
||||||
/// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH
|
/// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH
|
||||||
/// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh
|
/// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh
|
||||||
/// set of ECHConfigs. If the retry also fails, clients should report a connection failure.
|
/// set of ECHConfigs. If the retry also fails, clients should report a connection failure.
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
#[corresponds(SSL_set1_ech_config_list)]
|
#[corresponds(SSL_set1_ech_config_list)]
|
||||||
pub fn set_ech_config_list(&mut self, ech_config_list: &[u8]) -> Result<(), ErrorStack> {
|
pub fn set_ech_config_list(&mut self, ech_config_list: &[u8]) -> Result<(), ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -3753,7 +3645,6 @@ impl SslRef {
|
||||||
/// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to
|
/// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to
|
||||||
/// recover from potential key mismatches. If the result is `Some`, the client should retry the
|
/// recover from potential key mismatches. If the result is `Some`, the client should retry the
|
||||||
/// connection using the returned `ECHConfigList`.
|
/// connection using the returned `ECHConfigList`.
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
#[corresponds(SSL_get0_ech_retry_configs)]
|
#[corresponds(SSL_get0_ech_retry_configs)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_ech_retry_configs(&self) -> Option<&[u8]> {
|
pub fn get_ech_retry_configs(&self) -> Option<&[u8]> {
|
||||||
|
|
@ -3776,7 +3667,6 @@ impl SslRef {
|
||||||
/// Clients should call this function during the certificate verification callback to
|
/// Clients should call this function during the certificate verification callback to
|
||||||
/// ensure the server's certificate is valid for the public name, which is required to
|
/// ensure the server's certificate is valid for the public name, which is required to
|
||||||
/// authenticate retry configs.
|
/// authenticate retry configs.
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
#[corresponds(SSL_get0_ech_name_override)]
|
#[corresponds(SSL_get0_ech_name_override)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_ech_name_override(&self) -> Option<&[u8]> {
|
pub fn get_ech_name_override(&self) -> Option<&[u8]> {
|
||||||
|
|
@ -3794,7 +3684,6 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether or not `SSL` negotiated ECH.
|
// Whether or not `SSL` negotiated ECH.
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
#[corresponds(SSL_ech_accepted)]
|
#[corresponds(SSL_ech_accepted)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn ech_accepted(&self) -> bool {
|
pub fn ech_accepted(&self) -> bool {
|
||||||
|
|
@ -3802,7 +3691,6 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether or not to enable ECH grease on `SSL`.
|
// Whether or not to enable ECH grease on `SSL`.
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
#[corresponds(SSL_set_enable_ech_grease)]
|
#[corresponds(SSL_set_enable_ech_grease)]
|
||||||
pub fn set_enable_ech_grease(&self, enable: bool) {
|
pub fn set_enable_ech_grease(&self, enable: bool) {
|
||||||
let enable = if enable { 1 } else { 0 };
|
let enable = if enable { 1 } else { 0 };
|
||||||
|
|
@ -3813,7 +3701,6 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the compliance policy on `SSL`.
|
/// Sets the compliance policy on `SSL`.
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
#[corresponds(SSL_set_compliance_policy)]
|
#[corresponds(SSL_set_compliance_policy)]
|
||||||
pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> {
|
pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> {
|
||||||
unsafe { cvt_0i(ffi::SSL_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) }
|
unsafe { cvt_0i(ffi::SSL_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) }
|
||||||
|
|
@ -3882,10 +3769,11 @@ impl<S> MidHandshakeSslStream<S> {
|
||||||
Ok(self.stream)
|
Ok(self.stream)
|
||||||
} else {
|
} else {
|
||||||
self.error = self.stream.make_error(ret);
|
self.error = self.stream.make_error(ret);
|
||||||
match self.error.would_block() {
|
Err(if self.error.would_block() {
|
||||||
true => Err(HandshakeError::WouldBlock(self)),
|
HandshakeError::WouldBlock(self)
|
||||||
false => Err(HandshakeError::Failure(self)),
|
} else {
|
||||||
}
|
HandshakeError::Failure(self)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3920,26 +3808,23 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Read + Write> SslStream<S> {
|
impl<S: Read + Write> SslStream<S> {
|
||||||
fn new_base(ssl: Ssl, stream: S) -> Self {
|
|
||||||
unsafe {
|
|
||||||
let (bio, method) = bio::new(stream).unwrap();
|
|
||||||
ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
|
|
||||||
|
|
||||||
SslStream {
|
|
||||||
ssl: ManuallyDrop::new(ssl),
|
|
||||||
method: ManuallyDrop::new(method),
|
|
||||||
_p: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `SslStream`.
|
/// Creates a new `SslStream`.
|
||||||
///
|
///
|
||||||
/// This function performs no IO; the stream will not have performed any part of the handshake
|
/// This function performs no IO; the stream will not have performed any part of the handshake
|
||||||
/// with the peer. The `connect` and `accept` methods can be used to
|
/// with the peer. The `connect` and `accept` methods can be used to
|
||||||
/// explicitly perform the handshake.
|
/// explicitly perform the handshake.
|
||||||
pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
|
pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
|
||||||
Ok(Self::new_base(ssl, stream))
|
let (bio, method) = bio::new(stream)?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SslStream {
|
||||||
|
ssl: ManuallyDrop::new(ssl),
|
||||||
|
method: ManuallyDrop::new(method),
|
||||||
|
_p: PhantomData,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct.
|
/// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct.
|
||||||
|
|
@ -3951,7 +3836,7 @@ impl<S: Read + Write> SslStream<S> {
|
||||||
/// The caller must ensure the pointer is valid.
|
/// The caller must ensure the pointer is valid.
|
||||||
pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self {
|
pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self {
|
||||||
let ssl = Ssl::from_ptr(ssl);
|
let ssl = Ssl::from_ptr(ssl);
|
||||||
Self::new_base(ssl, stream)
|
Self::new(ssl, stream).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `read`, but takes a possibly-uninitialized slice.
|
/// Like `read`, but takes a possibly-uninitialized slice.
|
||||||
|
|
@ -4218,7 +4103,7 @@ where
|
||||||
/// Begin creating an `SslStream` atop `stream`
|
/// Begin creating an `SslStream` atop `stream`
|
||||||
pub fn new(ssl: Ssl, stream: S) -> Self {
|
pub fn new(ssl: Ssl, stream: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: SslStream::new_base(ssl, stream),
|
inner: SslStream::new(ssl, stream).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4243,9 +4128,6 @@ where
|
||||||
pub fn setup_connect(mut self) -> MidHandshakeSslStream<S> {
|
pub fn setup_connect(mut self) -> MidHandshakeSslStream<S> {
|
||||||
self.set_connect_state();
|
self.set_connect_state();
|
||||||
|
|
||||||
#[cfg(feature = "kx-safe-default")]
|
|
||||||
self.inner.ssl.client_set_default_curves_list();
|
|
||||||
|
|
||||||
MidHandshakeSslStream {
|
MidHandshakeSslStream {
|
||||||
stream: self.inner,
|
stream: self.inner,
|
||||||
error: Error {
|
error: Error {
|
||||||
|
|
@ -4275,9 +4157,6 @@ where
|
||||||
pub fn setup_accept(mut self) -> MidHandshakeSslStream<S> {
|
pub fn setup_accept(mut self) -> MidHandshakeSslStream<S> {
|
||||||
self.set_accept_state();
|
self.set_accept_state();
|
||||||
|
|
||||||
#[cfg(feature = "kx-safe-default")]
|
|
||||||
self.inner.ssl.server_set_default_curves_list();
|
|
||||||
|
|
||||||
MidHandshakeSslStream {
|
MidHandshakeSslStream {
|
||||||
stream: self.inner,
|
stream: self.inner,
|
||||||
error: Error {
|
error: Error {
|
||||||
|
|
@ -4309,16 +4188,11 @@ where
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
} else {
|
} else {
|
||||||
let error = stream.make_error(ret);
|
let error = stream.make_error(ret);
|
||||||
match error.would_block() {
|
Err(if error.would_block() {
|
||||||
true => Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
|
HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error })
|
||||||
stream,
|
} else {
|
||||||
error,
|
HandshakeError::Failure(MidHandshakeSslStream { stream, error })
|
||||||
})),
|
})
|
||||||
false => Err(HandshakeError::Failure(MidHandshakeSslStream {
|
|
||||||
stream,
|
|
||||||
error,
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,26 +13,24 @@ use crate::pkey::PKey;
|
||||||
use crate::srtp::SrtpProfileId;
|
use crate::srtp::SrtpProfileId;
|
||||||
use crate::ssl::test::server::Server;
|
use crate::ssl::test::server::Server;
|
||||||
use crate::ssl::SslVersion;
|
use crate::ssl::SslVersion;
|
||||||
use crate::ssl::{self, SslCurve};
|
|
||||||
use crate::ssl::{
|
use crate::ssl::{
|
||||||
ExtensionType, ShutdownResult, ShutdownState, Ssl, SslAcceptor, SslAcceptorBuilder,
|
self, ExtensionType, ShutdownResult, ShutdownState, Ssl, SslAcceptor, SslAcceptorBuilder,
|
||||||
SslConnector, SslContext, SslFiletype, SslMethod, SslOptions, SslStream, SslVerifyMode,
|
SslConnector, SslContext, SslFiletype, SslMethod, SslOptions, SslStream, SslVerifyMode,
|
||||||
};
|
};
|
||||||
use crate::x509::store::X509StoreBuilder;
|
use crate::x509::store::X509StoreBuilder;
|
||||||
use crate::x509::verify::X509CheckFlags;
|
use crate::x509::verify::X509CheckFlags;
|
||||||
use crate::x509::{X509Name, X509};
|
use crate::x509::{X509Name, X509};
|
||||||
|
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
use super::CompliancePolicy;
|
use super::CompliancePolicy;
|
||||||
|
|
||||||
mod cert_compressor;
|
mod cert_compressor;
|
||||||
mod cert_verify;
|
mod cert_verify;
|
||||||
mod custom_verify;
|
mod custom_verify;
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
mod ech;
|
mod ech;
|
||||||
mod private_key_method;
|
mod private_key_method;
|
||||||
mod server;
|
mod server;
|
||||||
mod session;
|
mod session;
|
||||||
|
mod session_resumption;
|
||||||
mod verify;
|
mod verify;
|
||||||
|
|
||||||
static ROOT_CERT: &[u8] = include_bytes!("../../../test/root-ca.pem");
|
static ROOT_CERT: &[u8] = include_bytes!("../../../test/root-ca.pem");
|
||||||
|
|
@ -954,59 +952,15 @@ fn sni_callback_swapped_ctx() {
|
||||||
assert!(CALLED_BACK.load(Ordering::SeqCst));
|
assert!(CALLED_BACK.load(Ordering::SeqCst));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "kx-safe-default")]
|
|
||||||
#[test]
|
|
||||||
fn client_set_default_curves_list() {
|
|
||||||
let ssl_ctx = crate::ssl::SslContextBuilder::new(SslMethod::tls())
|
|
||||||
.unwrap()
|
|
||||||
.build();
|
|
||||||
let mut ssl = Ssl::new(&ssl_ctx).unwrap();
|
|
||||||
|
|
||||||
// Panics if Kyber768 missing in boringSSL.
|
|
||||||
ssl.client_set_default_curves_list();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "kx-safe-default")]
|
|
||||||
#[test]
|
|
||||||
fn server_set_default_curves_list() {
|
|
||||||
let ssl_ctx = crate::ssl::SslContextBuilder::new(SslMethod::tls())
|
|
||||||
.unwrap()
|
|
||||||
.build();
|
|
||||||
let mut ssl = Ssl::new(&ssl_ctx).unwrap();
|
|
||||||
|
|
||||||
// Panics if Kyber768 missing in boringSSL.
|
|
||||||
ssl.server_set_default_curves_list();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_curve() {
|
fn get_curve() {
|
||||||
let server = Server::builder().build();
|
let server = Server::builder().build();
|
||||||
let client = server.client_with_root_ca();
|
let client = server.client_with_root_ca();
|
||||||
let client_stream = client.connect();
|
let client_stream = client.connect();
|
||||||
let curve = client_stream.ssl().curve().expect("curve");
|
let curve = client_stream.ssl().curve();
|
||||||
assert!(curve.name().is_some());
|
assert!(curve.is_some());
|
||||||
}
|
let curve_name = client_stream.ssl().curve_name();
|
||||||
|
assert!(curve_name.is_some());
|
||||||
#[test]
|
|
||||||
fn get_curve_name() {
|
|
||||||
assert_eq!(SslCurve::SECP224R1.name(), Some("P-224"));
|
|
||||||
assert_eq!(SslCurve::SECP256R1.name(), Some("P-256"));
|
|
||||||
assert_eq!(SslCurve::SECP384R1.name(), Some("P-384"));
|
|
||||||
assert_eq!(SslCurve::SECP521R1.name(), Some("P-521"));
|
|
||||||
assert_eq!(SslCurve::X25519.name(), Some("X25519"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "kx-safe-default"))]
|
|
||||||
#[test]
|
|
||||||
fn set_curves() {
|
|
||||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
|
||||||
ctx.set_curves(&[
|
|
||||||
SslCurve::SECP224R1,
|
|
||||||
SslCurve::SECP256R1,
|
|
||||||
SslCurve::SECP384R1,
|
|
||||||
SslCurve::X25519,
|
|
||||||
])
|
|
||||||
.expect("Failed to set curves");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -1037,7 +991,6 @@ fn test_get_ciphers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "fips"))]
|
|
||||||
fn test_set_compliance() {
|
fn test_set_compliance() {
|
||||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||||
ctx.set_compliance_policy(CompliancePolicy::FIPS_202205)
|
ctx.set_compliance_policy(CompliancePolicy::FIPS_202205)
|
||||||
|
|
@ -1118,7 +1071,6 @@ fn test_info_callback() {
|
||||||
assert!(CALLED_BACK.load(Ordering::Relaxed));
|
assert!(CALLED_BACK.load(Ordering::Relaxed));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ssl_set_compliance() {
|
fn test_ssl_set_compliance() {
|
||||||
let ctx = SslContext::builder(SslMethod::tls()).unwrap().build();
|
let ctx = SslContext::builder(SslMethod::tls()).unwrap().build();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
use super::server::Server;
|
||||||
|
use crate::ssl::test::MessageDigest;
|
||||||
|
use crate::ssl::HmacCtxRef;
|
||||||
|
use crate::ssl::SslRef;
|
||||||
|
use crate::ssl::SslSession;
|
||||||
|
use crate::ssl::SslSessionCacheMode;
|
||||||
|
use crate::ssl::TicketKeyCallbackResult;
|
||||||
|
use crate::symm::Cipher;
|
||||||
|
use crate::symm::CipherCtxRef;
|
||||||
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
static SUCCESS_ENCRYPTION_CALLED_BACK: AtomicU8 = AtomicU8::new(0);
|
||||||
|
static SUCCESS_DECRYPTION_CALLED_BACK: AtomicU8 = AtomicU8::new(0);
|
||||||
|
static NOOP_ENCRYPTION_CALLED_BACK: AtomicU8 = AtomicU8::new(0);
|
||||||
|
static NOOP_DECRYPTION_CALLED_BACK: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resume_session() {
|
||||||
|
static SESSION_TICKET: OnceLock<SslSession> = OnceLock::new();
|
||||||
|
static NST_RECIEVED_COUNT: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
let mut server = Server::builder();
|
||||||
|
server.expected_connections_count(2);
|
||||||
|
let server = server.build();
|
||||||
|
|
||||||
|
let mut client = server.client();
|
||||||
|
client
|
||||||
|
.ctx()
|
||||||
|
.set_session_cache_mode(SslSessionCacheMode::CLIENT);
|
||||||
|
client.ctx().set_new_session_callback(|_, session| {
|
||||||
|
NST_RECIEVED_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
// The server sends multiple session tickets but we only care to retrieve one.
|
||||||
|
let _ = SESSION_TICKET.set(session);
|
||||||
|
});
|
||||||
|
let ssl_stream = client.connect();
|
||||||
|
|
||||||
|
assert!(!ssl_stream.ssl().session_reused());
|
||||||
|
assert!(SESSION_TICKET.get().is_some());
|
||||||
|
assert_eq!(NST_RECIEVED_COUNT.load(Ordering::SeqCst), 2);
|
||||||
|
|
||||||
|
// Retrieve the session ticket
|
||||||
|
let session_ticket = SESSION_TICKET.get().unwrap();
|
||||||
|
|
||||||
|
// Attempt to resume the connection using the session ticket
|
||||||
|
let client_2 = server.client();
|
||||||
|
let mut ssl_builder = client_2.build().builder();
|
||||||
|
unsafe { ssl_builder.ssl().set_session(session_ticket).unwrap() };
|
||||||
|
let ssl_stream_2 = ssl_builder.connect();
|
||||||
|
|
||||||
|
assert!(ssl_stream_2.ssl().session_reused());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_callback_success() {
|
||||||
|
static SESSION_TICKET: OnceLock<SslSession> = OnceLock::new();
|
||||||
|
static NST_RECIEVED_COUNT: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
let mut server = Server::builder();
|
||||||
|
server.expected_connections_count(2);
|
||||||
|
unsafe {
|
||||||
|
server
|
||||||
|
.ctx()
|
||||||
|
.set_ticket_key_callback(test_success_tickey_key_callback)
|
||||||
|
};
|
||||||
|
let server = server.build();
|
||||||
|
|
||||||
|
let mut client = server.client();
|
||||||
|
client
|
||||||
|
.ctx()
|
||||||
|
.set_session_cache_mode(SslSessionCacheMode::CLIENT);
|
||||||
|
client.ctx().set_new_session_callback(|_, session| {
|
||||||
|
NST_RECIEVED_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
// The server sends multiple session tickets but we only care to retrieve one.
|
||||||
|
let _ = SESSION_TICKET.set(session);
|
||||||
|
});
|
||||||
|
let ssl_stream = client.connect();
|
||||||
|
|
||||||
|
assert!(!ssl_stream.ssl().session_reused());
|
||||||
|
assert!(SESSION_TICKET.get().is_some());
|
||||||
|
assert_eq!(SUCCESS_ENCRYPTION_CALLED_BACK.load(Ordering::SeqCst), 2);
|
||||||
|
assert_eq!(SUCCESS_DECRYPTION_CALLED_BACK.load(Ordering::SeqCst), 0);
|
||||||
|
assert_eq!(NST_RECIEVED_COUNT.load(Ordering::SeqCst), 2);
|
||||||
|
|
||||||
|
// Retrieve the session ticket
|
||||||
|
let session_ticket = SESSION_TICKET.get().unwrap();
|
||||||
|
|
||||||
|
// Attempt to resume the connection using the session ticket
|
||||||
|
let client_2 = server.client();
|
||||||
|
let mut ssl_builder = client_2.build().builder();
|
||||||
|
unsafe { ssl_builder.ssl().set_session(session_ticket).unwrap() };
|
||||||
|
let ssl_stream_2 = ssl_builder.connect();
|
||||||
|
|
||||||
|
assert!(ssl_stream_2.ssl().session_reused());
|
||||||
|
assert_eq!(SUCCESS_ENCRYPTION_CALLED_BACK.load(Ordering::SeqCst), 4);
|
||||||
|
assert_eq!(SUCCESS_DECRYPTION_CALLED_BACK.load(Ordering::SeqCst), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_callback_unrecognized_decryption_ticket() {
|
||||||
|
static SESSION_TICKET: OnceLock<SslSession> = OnceLock::new();
|
||||||
|
static NST_RECIEVED_COUNT: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
let mut server = Server::builder();
|
||||||
|
server.expected_connections_count(2);
|
||||||
|
unsafe {
|
||||||
|
server
|
||||||
|
.ctx()
|
||||||
|
.set_ticket_key_callback(test_noop_tickey_key_callback)
|
||||||
|
};
|
||||||
|
let server = server.build();
|
||||||
|
|
||||||
|
let mut client = server.client();
|
||||||
|
client
|
||||||
|
.ctx()
|
||||||
|
.set_session_cache_mode(SslSessionCacheMode::CLIENT);
|
||||||
|
client.ctx().set_new_session_callback(|_, session| {
|
||||||
|
NST_RECIEVED_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
// The server sends multiple session tickets but we only care to retrieve one.
|
||||||
|
let _ = SESSION_TICKET.set(session);
|
||||||
|
});
|
||||||
|
let ssl_stream = client.connect();
|
||||||
|
|
||||||
|
assert!(!ssl_stream.ssl().session_reused());
|
||||||
|
assert!(SESSION_TICKET.get().is_some());
|
||||||
|
assert_eq!(NOOP_ENCRYPTION_CALLED_BACK.load(Ordering::SeqCst), 2);
|
||||||
|
assert_eq!(NOOP_DECRYPTION_CALLED_BACK.load(Ordering::SeqCst), 0);
|
||||||
|
assert_eq!(NST_RECIEVED_COUNT.load(Ordering::SeqCst), 2);
|
||||||
|
|
||||||
|
// Retrieve the session ticket
|
||||||
|
let session_ticket = SESSION_TICKET.get().unwrap();
|
||||||
|
|
||||||
|
// Attempt to resume the connection using the session ticket
|
||||||
|
let client_2 = server.client();
|
||||||
|
let mut ssl_builder = client_2.build().builder();
|
||||||
|
unsafe { ssl_builder.ssl().set_session(session_ticket).unwrap() };
|
||||||
|
let ssl_stream_2 = ssl_builder.connect();
|
||||||
|
|
||||||
|
// Second connection was NOT resumed due to TicketKeyCallbackResult::Noop on decryption
|
||||||
|
assert!(!ssl_stream_2.ssl().session_reused());
|
||||||
|
assert_eq!(NOOP_ENCRYPTION_CALLED_BACK.load(Ordering::SeqCst), 4);
|
||||||
|
assert_eq!(NOOP_DECRYPTION_CALLED_BACK.load(Ordering::SeqCst), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully return a session ticket in encryption mode but return a
|
||||||
|
// TicketKeyCallbackResult::Noop in decryption mode.
|
||||||
|
fn test_noop_tickey_key_callback(
|
||||||
|
_ssl: &SslRef,
|
||||||
|
key_name: &mut [u8; 16],
|
||||||
|
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
evp_ctx: &mut CipherCtxRef,
|
||||||
|
hmac_ctx: &mut HmacCtxRef,
|
||||||
|
encrypt: bool,
|
||||||
|
) -> TicketKeyCallbackResult {
|
||||||
|
// These should only be used for testing purposes.
|
||||||
|
const TEST_KEY_NAME: [u8; 16] = [5; 16];
|
||||||
|
const TEST_CBC_IV: [u8; ffi::EVP_MAX_IV_LENGTH as usize] = [1; ffi::EVP_MAX_IV_LENGTH as usize];
|
||||||
|
const TEST_AES_128_CBC_KEY: [u8; 16] = [2; 16];
|
||||||
|
const TEST_HMAC_KEY: [u8; 32] = [3; 32];
|
||||||
|
|
||||||
|
let digest = MessageDigest::sha256();
|
||||||
|
let cipher = Cipher::aes_128_cbc();
|
||||||
|
|
||||||
|
if encrypt {
|
||||||
|
NOOP_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// Ensure key_name and iv are initialized and set test values.
|
||||||
|
assert_eq!(key_name, &[0; 16]);
|
||||||
|
assert_eq!(iv, &[0; 16]);
|
||||||
|
key_name.copy_from_slice(&TEST_KEY_NAME);
|
||||||
|
iv.copy_from_slice(&TEST_CBC_IV);
|
||||||
|
|
||||||
|
// Set the encryption context.
|
||||||
|
evp_ctx
|
||||||
|
.init_encrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Set the hmac context.
|
||||||
|
hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap();
|
||||||
|
|
||||||
|
TicketKeyCallbackResult::Success
|
||||||
|
} else {
|
||||||
|
NOOP_DECRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// Check key_name matches.
|
||||||
|
assert_eq!(key_name, &TEST_KEY_NAME);
|
||||||
|
|
||||||
|
TicketKeyCallbackResult::Noop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom callback to encrypt and decrypt session tickets
|
||||||
|
fn test_success_tickey_key_callback(
|
||||||
|
_ssl: &SslRef,
|
||||||
|
key_name: &mut [u8; 16],
|
||||||
|
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
evp_ctx: &mut CipherCtxRef,
|
||||||
|
hmac_ctx: &mut HmacCtxRef,
|
||||||
|
encrypt: bool,
|
||||||
|
) -> TicketKeyCallbackResult {
|
||||||
|
// These should only be used for testing purposes.
|
||||||
|
const TEST_KEY_NAME: [u8; 16] = [5; 16];
|
||||||
|
const TEST_CBC_IV: [u8; ffi::EVP_MAX_IV_LENGTH as usize] = [1; ffi::EVP_MAX_IV_LENGTH as usize];
|
||||||
|
const TEST_AES_128_CBC_KEY: [u8; 16] = [2; 16];
|
||||||
|
const TEST_HMAC_KEY: [u8; 32] = [3; 32];
|
||||||
|
|
||||||
|
let digest = MessageDigest::sha256();
|
||||||
|
let cipher = Cipher::aes_128_cbc();
|
||||||
|
|
||||||
|
if encrypt {
|
||||||
|
SUCCESS_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// Ensure key_name and iv are initialized and set test values.
|
||||||
|
assert_eq!(key_name, &[0; 16]);
|
||||||
|
assert_eq!(iv, &[0; 16]);
|
||||||
|
key_name.copy_from_slice(&TEST_KEY_NAME);
|
||||||
|
iv.copy_from_slice(&TEST_CBC_IV);
|
||||||
|
|
||||||
|
// Set the encryption context.
|
||||||
|
evp_ctx
|
||||||
|
.init_encrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Set the hmac context.
|
||||||
|
hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap();
|
||||||
|
} else {
|
||||||
|
SUCCESS_DECRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// Check key_name matches.
|
||||||
|
assert_eq!(key_name, &TEST_KEY_NAME);
|
||||||
|
|
||||||
|
// Set the decryption context.
|
||||||
|
evp_ctx
|
||||||
|
.init_decrypt(&cipher, &TEST_AES_128_CBC_KEY, iv)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Set the hmac context.
|
||||||
|
hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
TicketKeyCallbackResult::Success
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,9 @@ foreign_type_and_impl_send_sync! {
|
||||||
type CType = c_char;
|
type CType = c_char;
|
||||||
fn drop = free;
|
fn drop = free;
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// MUST be UTF-8.
|
||||||
pub struct OpensslString;
|
pub struct OpensslString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
use foreign_types::ForeignTypeRef;
|
||||||
use libc::{c_int, c_uint};
|
use libc::{c_int, c_uint};
|
||||||
use openssl_macros::corresponds;
|
use openssl_macros::corresponds;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
@ -68,6 +69,71 @@ pub enum Mode {
|
||||||
Decrypt,
|
Decrypt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreign_type_and_impl_send_sync! {
|
||||||
|
type CType = ffi::EVP_CIPHER_CTX;
|
||||||
|
fn drop = ffi::EVP_CIPHER_CTX_free;
|
||||||
|
|
||||||
|
pub struct CipherCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CipherCtxRef {
|
||||||
|
/// Configures CipherCtx for a fresh encryption operation using `cipher`.
|
||||||
|
///
|
||||||
|
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/cipher.h.html#EVP_EncryptInit_ex
|
||||||
|
pub fn init_encrypt(
|
||||||
|
&mut self,
|
||||||
|
cipher: &Cipher,
|
||||||
|
key: &[u8],
|
||||||
|
iv: &[u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
) -> Result<(), ErrorStack> {
|
||||||
|
ffi::init();
|
||||||
|
|
||||||
|
if key.len() != cipher.key_len() {
|
||||||
|
return Err(ErrorStack::internal_error_str("invalid key size"));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_EncryptInit_ex(
|
||||||
|
self.as_ptr(),
|
||||||
|
cipher.as_ptr(),
|
||||||
|
// ENGINE api is deprecated
|
||||||
|
ptr::null_mut(),
|
||||||
|
key.as_ptr(),
|
||||||
|
iv.as_ptr(),
|
||||||
|
))
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configures CipherCtx for a fresh decryption operation using `cipher`.
|
||||||
|
///
|
||||||
|
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/cipher.h.html#EVP_DecryptInit_ex
|
||||||
|
pub fn init_decrypt(
|
||||||
|
&mut self,
|
||||||
|
cipher: &Cipher,
|
||||||
|
key: &[u8],
|
||||||
|
iv: &[u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
) -> Result<(), ErrorStack> {
|
||||||
|
ffi::init();
|
||||||
|
|
||||||
|
if key.len() != cipher.key_len() {
|
||||||
|
return Err(ErrorStack::internal_error_str("invalid key size"));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_DecryptInit_ex(
|
||||||
|
self.as_ptr(),
|
||||||
|
cipher.as_ptr(),
|
||||||
|
// ENGINE api is deprecated
|
||||||
|
ptr::null_mut(),
|
||||||
|
key.as_ptr(),
|
||||||
|
iv.as_ptr(),
|
||||||
|
))
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a particular cipher algorithm.
|
/// Represents a particular cipher algorithm.
|
||||||
///
|
///
|
||||||
/// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms.
|
/// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms.
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ where
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(Ok(len)) => len as c_int,
|
Ok(Ok(len)) => len as c_int,
|
||||||
Ok(Err(_)) => {
|
Ok(Err(err)) => {
|
||||||
// FIXME restore error stack
|
err.put();
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ use std::mem;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::sync::{LazyLock, Once};
|
use std::sync::{LazyLock, Once};
|
||||||
|
|
||||||
|
|
@ -485,16 +484,9 @@ impl X509Builder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an X509 extension value to the certificate.
|
|
||||||
///
|
|
||||||
/// This works just as `append_extension` except it takes ownership of the `X509Extension`.
|
|
||||||
pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
|
|
||||||
self.append_extension2(&extension)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds an X509 extension value to the certificate.
|
/// Adds an X509 extension value to the certificate.
|
||||||
#[corresponds(X509_add_ext)]
|
#[corresponds(X509_add_ext)]
|
||||||
pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
|
pub fn append_extension(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
|
cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -865,7 +857,7 @@ impl fmt::Debug for X509 {
|
||||||
|
|
||||||
if let Ok(public_key) = &self.public_key() {
|
if let Ok(public_key) = &self.public_key() {
|
||||||
debug_struct.field("public_key", public_key);
|
debug_struct.field("public_key", public_key);
|
||||||
};
|
}
|
||||||
// TODO: Print extensions once they are supported on the X509 struct.
|
// TODO: Print extensions once they are supported on the X509 struct.
|
||||||
|
|
||||||
debug_struct.finish()
|
debug_struct.finish()
|
||||||
|
|
@ -1121,9 +1113,9 @@ impl X509NameBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
#[cfg(not(feature = "legacy-compat-deprecated"))]
|
||||||
type ValueLen = isize;
|
type ValueLen = isize;
|
||||||
#[cfg(feature = "fips-compat")]
|
#[cfg(feature = "legacy-compat-deprecated")]
|
||||||
type ValueLen = i32;
|
type ValueLen = i32;
|
||||||
|
|
||||||
foreign_type_and_impl_send_sync! {
|
foreign_type_and_impl_send_sync! {
|
||||||
|
|
@ -1535,6 +1527,8 @@ impl X509VerifyError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a human readable error string from the verification error.
|
/// Return a human readable error string from the verification error.
|
||||||
|
///
|
||||||
|
/// Returns empty string if the message was not UTF-8.
|
||||||
#[corresponds(X509_verify_cert_error_string)]
|
#[corresponds(X509_verify_cert_error_string)]
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -1543,7 +1537,7 @@ impl X509VerifyError {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let s = ffi::X509_verify_cert_error_string(c_long::from(self.0));
|
let s = ffi::X509_verify_cert_error_string(c_long::from(self.0));
|
||||||
str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
|
CStr::from_ptr(s).to_str().unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1695,14 +1689,12 @@ impl GeneralNameRef {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ia5 as *mut _);
|
let asn = Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ia5);
|
||||||
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ia5 as *mut _);
|
|
||||||
|
|
||||||
let slice = slice::from_raw_parts(ptr, len as usize);
|
|
||||||
// IA5Strings are stated to be ASCII (specifically IA5). Hopefully
|
// IA5Strings are stated to be ASCII (specifically IA5). Hopefully
|
||||||
// OpenSSL checks that when loading a certificate but if not we'll
|
// OpenSSL checks that when loading a certificate but if not we'll
|
||||||
// use this instead of from_utf8_unchecked just in case.
|
// use this instead of from_utf8_unchecked just in case.
|
||||||
str::from_utf8(slice).ok()
|
asn.to_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1732,10 +1724,7 @@ impl GeneralNameRef {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ip as *mut _);
|
Some(Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ip).as_slice())
|
||||||
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ip as *mut _);
|
|
||||||
|
|
||||||
Some(slice::from_raw_parts(ptr, len as usize))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1811,8 +1800,8 @@ impl Stackable for X509Object {
|
||||||
use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
|
use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
|
||||||
|
|
||||||
use crate::ffi::{
|
use crate::ffi::{
|
||||||
ASN1_STRING_get0_data, X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version,
|
X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version, X509_STORE_CTX_get0_chain,
|
||||||
X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore,
|
X509_set1_notAfter, X509_set1_notBefore,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ffi::X509_OBJECT_get0_X509;
|
use crate::ffi::X509_OBJECT_get0_X509;
|
||||||
|
|
|
||||||
|
|
@ -250,34 +250,36 @@ fn x509_builder() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let basic_constraints = BasicConstraints::new().critical().ca().build().unwrap();
|
let basic_constraints = BasicConstraints::new().critical().ca().build().unwrap();
|
||||||
builder.append_extension(basic_constraints).unwrap();
|
builder
|
||||||
|
.append_extension(basic_constraints.as_ref())
|
||||||
|
.unwrap();
|
||||||
let key_usage = KeyUsage::new()
|
let key_usage = KeyUsage::new()
|
||||||
.digital_signature()
|
.digital_signature()
|
||||||
.key_encipherment()
|
.key_encipherment()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
builder.append_extension(key_usage).unwrap();
|
builder.append_extension(&key_usage).unwrap();
|
||||||
let ext_key_usage = ExtendedKeyUsage::new()
|
let ext_key_usage = ExtendedKeyUsage::new()
|
||||||
.client_auth()
|
.client_auth()
|
||||||
.server_auth()
|
.server_auth()
|
||||||
.other("2.999.1")
|
.other("2.999.1")
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
builder.append_extension(ext_key_usage).unwrap();
|
builder.append_extension(&ext_key_usage).unwrap();
|
||||||
let subject_key_identifier = SubjectKeyIdentifier::new()
|
let subject_key_identifier = SubjectKeyIdentifier::new()
|
||||||
.build(&builder.x509v3_context(None, None))
|
.build(&builder.x509v3_context(None, None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
builder.append_extension(subject_key_identifier).unwrap();
|
builder.append_extension(&subject_key_identifier).unwrap();
|
||||||
let authority_key_identifier = AuthorityKeyIdentifier::new()
|
let authority_key_identifier = AuthorityKeyIdentifier::new()
|
||||||
.keyid(true)
|
.keyid(true)
|
||||||
.build(&builder.x509v3_context(None, None))
|
.build(&builder.x509v3_context(None, None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
builder.append_extension(authority_key_identifier).unwrap();
|
builder.append_extension(&authority_key_identifier).unwrap();
|
||||||
let subject_alternative_name = SubjectAlternativeName::new()
|
let subject_alternative_name = SubjectAlternativeName::new()
|
||||||
.dns("example.com")
|
.dns("example.com")
|
||||||
.build(&builder.x509v3_context(None, None))
|
.build(&builder.x509v3_context(None, None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
builder.append_extension(subject_alternative_name).unwrap();
|
builder.append_extension(&subject_alternative_name).unwrap();
|
||||||
|
|
||||||
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ fn test_verify_cert() {
|
||||||
|
|
||||||
assert_eq!(Ok(()), verify(&leaf, &[&root1], &[&intermediate], |_| {}));
|
assert_eq!(Ok(()), verify(&leaf, &[&root1], &[&intermediate], |_| {}));
|
||||||
|
|
||||||
#[cfg(not(feature = "fips-compat"))]
|
#[cfg(not(feature = "legacy-compat-deprecated"))]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok(()),
|
Ok(()),
|
||||||
verify(
|
verify(
|
||||||
|
|
@ -26,7 +26,7 @@ fn test_verify_cert() {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "fips-compat")]
|
#[cfg(feature = "legacy-compat-deprecated")]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(X509VerifyError::CERT_HAS_EXPIRED),
|
Err(X509VerifyError::CERT_HAS_EXPIRED),
|
||||||
verify(
|
verify(
|
||||||
|
|
@ -61,7 +61,7 @@ fn test_verify_cert() {
|
||||||
Ok(()),
|
Ok(()),
|
||||||
verify(&leaf, &[&root1], &[&intermediate, &root1_cross], |param| {
|
verify(&leaf, &[&root1], &[&intermediate, &root1_cross], |param| {
|
||||||
param.clear_flags(X509Flags::TRUSTED_FIRST)
|
param.clear_flags(X509Flags::TRUSTED_FIRST)
|
||||||
},)
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,29 +12,12 @@ An implementation of SSL streams for Compio backed by BoringSSL
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["pq-experimental"]
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Use a FIPS-validated version of boringssl.
|
# Use a FIPS-validated version of boringssl.
|
||||||
fips = ["boring/fips", "boring-sys/fips"]
|
fips = ["boring/fips", "boring-sys/fips"]
|
||||||
|
|
||||||
# Use a FIPS build of BoringSSL, but don't set "fips-compat".
|
|
||||||
#
|
|
||||||
# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer
|
|
||||||
# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen,
|
|
||||||
# which means the "fips-compat" feature is no longer needed.
|
|
||||||
#
|
|
||||||
# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply
|
|
||||||
# "fips-compat".
|
|
||||||
fips-precompiled = ["boring/fips-precompiled"]
|
|
||||||
|
|
||||||
# Link with precompiled FIPS-validated `bcm.o` module.
|
|
||||||
fips-link-precompiled = ["boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"]
|
|
||||||
|
|
||||||
# Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/)
|
|
||||||
pq-experimental = ["boring/pq-experimental"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
boring = { workspace = true }
|
boring = { workspace = true }
|
||||||
boring-sys = { workspace = true }
|
boring-sys = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,8 @@ maintenance = { status = "passively-maintained" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["runtime-tokio"]
|
default = ["runtime-tokio"]
|
||||||
|
|
||||||
runtime-tokio = ["quinn/runtime-tokio"]
|
runtime-tokio = ["quinn/runtime-tokio"]
|
||||||
|
|
||||||
# Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/)
|
|
||||||
pq-experimental = ["boring/pq-experimental"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
boring = { workspace = true }
|
boring = { workspace = true }
|
||||||
boring-sys = { workspace = true }
|
boring-sys = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -12,29 +12,12 @@ An implementation of SSL streams for Tokio backed by BoringSSL
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["pq-experimental"]
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Use a FIPS-validated version of boringssl.
|
# Use a FIPS-validated version of boringssl.
|
||||||
fips = ["boring/fips", "boring-sys/fips"]
|
fips = ["boring/fips", "boring-sys/fips"]
|
||||||
|
|
||||||
# Use a FIPS build of BoringSSL, but don't set "fips-compat".
|
|
||||||
#
|
|
||||||
# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer
|
|
||||||
# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen,
|
|
||||||
# which means the "fips-compat" feature is no longer needed.
|
|
||||||
#
|
|
||||||
# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply
|
|
||||||
# "fips-compat".
|
|
||||||
fips-precompiled = ["boring/fips-precompiled"]
|
|
||||||
|
|
||||||
# Link with precompiled FIPS-validated `bcm.o` module.
|
|
||||||
fips-link-precompiled = ["boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"]
|
|
||||||
|
|
||||||
# Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/)
|
|
||||||
pq-experimental = ["boring/pq-experimental"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
boring = { workspace = true }
|
boring = { workspace = true }
|
||||||
boring-sys = { workspace = true }
|
boring-sys = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ impl<S> AsyncStreamBridge<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_waker(&mut self, ctx: Option<&mut Context<'_>>) {
|
pub(crate) fn set_waker(&mut self, ctx: Option<&mut Context<'_>>) {
|
||||||
self.waker = ctx.map(|ctx| ctx.waker().clone())
|
self.waker = ctx.map(|ctx| ctx.waker().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue