Merge in upstream v4.20.0

This commit is contained in:
Andrew 2026-01-14 14:42:20 -05:00
parent 81d4aa19ac
commit 7b684803ee
24 changed files with 394 additions and 241 deletions

View File

@ -18,8 +18,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable && rustup default stable
- name: Install Rustfmt
run: rustup default stable && rustup component add rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
@ -31,10 +31,11 @@ jobs:
with:
submodules: 'recursive'
- 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
id: rust-version
run: echo "::set-output name=version::$(rustc --version)"
run: |
echo "version=$(rustc --version)" >> $GITHUB_OUTPUT
- name: Cache cargo index
uses: actions/cache@v4
with:
@ -58,6 +59,10 @@ jobs:
key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}
- name: Run clippy
run: cargo clippy --all --all-targets
- name: Check docs
run: cargo doc --no-deps -p boring -p boring-sys --features rpk,pq-experimental,underscore-wildcards
env:
DOCS_RS: 1
test:
name: Test
runs-on: ${{ matrix.os }}
@ -141,8 +146,8 @@ jobs:
apt_packages: gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
check_only: true
custom_env:
CC: arm-linux-gnueabi-gcc
CXX: arm-linux-gnueabi-g++
CC_arm-unknown-linux-gnueabi: arm-linux-gnueabi-gcc
CXX_arm-unknown-linux-gnueabi: arm-linux-gnueabi-g++
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER: arm-linux-gnueabi-g++
- thing: aarch64-linux
target: aarch64-unknown-linux-gnu
@ -151,8 +156,8 @@ jobs:
apt_packages: crossbuild-essential-arm64
check_only: true
custom_env:
CC: aarch64-linux-gnu-gcc
CXX: aarch64-linux-gnu-g++
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-g++
- thing: arm64-macos
target: aarch64-apple-darwin

View File

@ -8,7 +8,7 @@ members = [
resolver = "2"
[workspace.package]
version = "4.18.0"
version = "4.20.0"
repository = "https://github.com/cloudflare/boring"
edition = "2021"
@ -19,16 +19,17 @@ tag-prefix = ""
publish = false
[workspace.dependencies]
boring-sys = { version = "4.18.0", path = "./boring-sys" }
boring = { version = "4.18.0", path = "./boring" }
tokio-boring = { version = "4.18.0", path = "./tokio-boring" }
boring-sys = { version = "4.19.0", path = "./boring-sys" }
boring = { version = "4.19.0", path = "./boring" }
tokio-boring = { version = "4.19.0", path = "./tokio-boring" }
bindgen = { version = "0.72.0", default-features = false, features = ["runtime"] }
bitflags = "2.9"
brotli = "8.0"
bytes = "1"
cmake = "0.1.18"
cmake = "0.1.54"
fs_extra = "1.3.0"
fslock = "0.2"
bitflags = "2.4"
foreign-types = "0.5"
libc = "0.2"
hex = "0.4"
@ -48,5 +49,3 @@ openssl-macros = "0.1.1"
tower = "0.4"
tower-layer = "0.3"
tower-service = "0.3"
autocfg = "1.3.0"
brotli = "6.0"

View File

@ -1,3 +1,24 @@
4.20.0
- 2025-08-26 Support TARGET_CC and CC_{target}
- 2025-08-26 Fix swapped host/target args
- 2025-06-13 CStr UTF-8 improvements
- 2025-09-26 Skip Rust version detection for bindgen
- 2025-09-26 Upgrade deps
- 2025-06-13 Ensure that ERR_LIB type can be named
- 2025-06-13 Add more reliable library_reason()
- 2025-09-30 pq: fix MSVC C4146 warning
- 2025-10-14 Freebsd build
- 2025-10-01 Fix string data conversion in ErrorStack::put()
4.19.0
- 2025-09-03 Add binding for X509_check_ip_asc
- 2025-06-13 Use ERR_clear_error
- 2025-06-13 Error descriptions and docs
- 2025-06-13 Boring doesn't use function codes
- 2025-09-03 Fix patched docs.rs builds
- 2025-09-03 Test docs.rs docs
- 2025-09-03 Fix doc links
4.18.0
- 2025-05-29 Add set_verify_param
- 2025-05-28 Add support for X509_STORE_CTX_get0_untrusted

View File

@ -13,6 +13,7 @@ build = "build/main.rs"
readme = "README.md"
categories = ["cryptography", "external-ffi-bindings"]
edition = { workspace = true }
rust-version = "1.77"
include = [
"/*.md",
"/*.toml",
@ -89,7 +90,6 @@ pq-experimental = []
underscore-wildcards = []
[build-dependencies]
autocfg = { workspace = true }
bindgen = { workspace = true }
cmake = { workspace = true }
fs_extra = { workspace = true }

View File

@ -36,6 +36,9 @@ pub(crate) struct Env {
pub(crate) android_ndk_home: Option<PathBuf>,
pub(crate) cmake_toolchain_file: Option<PathBuf>,
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,
}
@ -51,10 +54,10 @@ impl Config {
let features = Features::from_env();
let env = Env::from_env(&host, &target, features.is_fips_like());
let mut is_bazel = false;
if let Some(src_path) = &env.source_path {
is_bazel = src_path.join("src").exists();
}
let is_bazel = env
.source_path
.as_ref()
.is_some_and(|path| path.join("src").exists());
let config = Self {
manifest_dir,
@ -142,22 +145,19 @@ impl Features {
}
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 FIPS_PREFIX: &str = "BORING_BSSL_FIPS";
let var_prefix = if host == target { "HOST" } else { "TARGET" };
let target_with_underscores = target.replace('-', "_");
// Logic stolen from cmake-rs.
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
let target_only_var = |name: &str| {
var(&format!("{name}_{target}"))
.or_else(|| var(&format!("{name}_{target_with_underscores}")))
.or_else(|| var(&format!("{kind}_{name}")))
.or_else(|| var(name))
.or_else(|| var(&format!("{var_prefix}_{name}")))
};
let target_var = |name: &str| target_only_var(name).or_else(|| var(name));
let boringssl_var = |name: &str| {
// The passed name is the non-fips version of the environment variable,
@ -186,6 +186,9 @@ impl Env {
android_ndk_home: target_var("ANDROID_NDK_HOME").map(Into::into),
cmake_toolchain_file: target_var("CMAKE_TOOLCHAIN_FILE").map(Into::into),
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(),
}
}

View File

@ -152,7 +152,7 @@ fn get_boringssl_source_path(config: &Config) -> &PathBuf {
///
/// MSVC generator on Windows place static libs in a target sub-folder,
/// so adjust library location based on platform and build target.
/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
/// See issue: <https://github.com/alexcrichton/cmake-rs/issues/18>
fn get_boringssl_platform_output_path(config: &Config) -> String {
if config.target.ends_with("-msvc") {
// Code under this branch should match the logic in cmake-rs
@ -193,7 +193,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.
fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
@ -216,6 +216,15 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
.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 {
boringssl_cmake.define("CMAKE_SYSROOT", sysroot);
}
@ -331,7 +340,7 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config {
boringssl_cmake
}
/// Verify that the toolchains match https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3678.pdf
/// 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) {
@ -468,6 +477,24 @@ fn get_extra_clang_args_for_bindgen(config: &Config) -> Vec<String> {
}
fn ensure_patches_applied(config: &Config) -> io::Result<()> {
if config.env.assume_patched || config.env.path.is_some() {
println!(
"cargo:warning=skipping git patches application, provided\
native BoringSSL is expected to have the patches included"
);
return Ok(());
} else if config.env.source_path.is_some()
&& (config.features.rpk
|| config.features.pq_experimental
|| config.features.underscore_wildcards)
{
panic!(
"BORING_BSSL_ASSUME_PATCHED must be set when setting
BORING_BSSL_SOURCE_PATH and using any of the following
features: rpk, pq-experimental, underscore-wildcards"
);
}
let mut lock_file = LockFile::open(&config.out_dir.join(".patch_lock"))?;
let src_path = get_boringssl_source_path(config);
let has_git = src_path.join(".git").exists();
@ -552,25 +579,6 @@ fn built_boring_source_path(config: &Config) -> &PathBuf {
static BUILD_SOURCE_PATH: OnceLock<PathBuf> = OnceLock::new();
BUILD_SOURCE_PATH.get_or_init(|| {
if config.env.assume_patched {
println!(
"cargo:warning=skipping git patches application, provided\
native BoringSSL is expected to have the patches included"
);
} else if config.env.source_path.is_some()
&& (config.features.rpk
|| config.features.pq_experimental
|| config.features.underscore_wildcards)
{
panic!(
"BORING_BSSL_ASSUME_PATCHED must be set when setting
BORING_BSSL_SOURCE_PATH and using any of the following
features: rpk, pq-experimental, underscore-wildcards"
);
} else {
ensure_patches_applied(config).unwrap();
}
let mut cfg = get_boringssl_cmake_config(config);
let num_jobs = std::env::var("NUM_JOBS").ok().or_else(|| {
@ -651,7 +659,7 @@ fn get_cpp_runtime_lib(config: &Config) -> Option<String> {
// TODO(rmehra): figure out how to do this for windows
if env::var_os("CARGO_CFG_UNIX").is_some() {
match env::var("CARGO_CFG_TARGET_OS").unwrap().as_ref() {
"macos" | "ios" => Some("c++".into()),
"macos" | "ios" | "freebsd" => Some("c++".into()),
_ => Some("stdc++".into()),
}
} else {
@ -661,6 +669,7 @@ fn get_cpp_runtime_lib(config: &Config) -> Option<String> {
fn main() {
let config = Config::from_env();
ensure_patches_applied(&config).unwrap();
if !config.env.docs_rs {
emit_link_directives(&config);
}
@ -732,12 +741,8 @@ fn generate_bindings(config: &Config) {
}
});
// bindgen 0.70 replaced the run-time layout tests with compile-time ones,
// but they depend on std::mem::offset_of, stabilized in 1.77.
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 target_rust_version =
bindgen::RustTarget::stable(77, 0).expect("bindgen does not recognize target rust version");
let mut builder = bindgen::Builder::default()
.rust_target(target_rust_version) // bindgen MSRV is 1.70, so this is enough
@ -753,7 +758,7 @@ fn generate_bindings(config: &Config) {
.generate_comments(true)
.fit_macro_constants(false)
.size_t_is_usize(true)
.layout_tests(supports_layout_tests)
.layout_tests(config.env.debug.is_some())
.prepend_enum_name(true)
.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))
@ -805,7 +810,24 @@ fn generate_bindings(config: &Config) {
}
let bindings = builder.generate().expect("Unable to generate bindings");
let mut source_code = Vec::new();
bindings
.write_to_file(config.out_dir.join("bindings.rs"))
.expect("Couldn't write bindings!");
.write(Box::new(&mut source_code))
.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(),
);
}

View File

@ -940,7 +940,7 @@ index 776c085f9..ccb5b3d9b 100644
+ for(i=0;i<len;i++)
+ r |= a[i] ^ b[i];
+
+ return (-(uint64_t)r) >> 63;
+ return (0-(uint64_t)r) >> 63;
+}
+
+/*************************************************

View File

@ -147,7 +147,7 @@ fn real_main() -> Result<(), ErrorStack> {
match ca_cert.issued(&cert) {
Ok(()) => println!("Certificate verified!"),
Err(ver_err) => println!("Failed to verify certificate: {ver_err}"),
};
}
Ok(())
}
@ -156,5 +156,5 @@ fn main() {
match real_main() {
Ok(()) => println!("Finished."),
Err(e) => println!("Error: {e}"),
};
}
}

View File

@ -63,20 +63,19 @@ foreign_type_and_impl_send_sync! {
impl fmt::Display for Asn1GeneralizedTimeRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
let mem_bio = match MemBio::new() {
Err(_) => return f.write_str("error"),
Ok(m) => m,
};
let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print(
mem_bio.as_ptr(),
self.as_ptr(),
));
match print_result {
Err(_) => f.write_str("error"),
Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
}
}
let bio = MemBio::new().ok();
let msg = bio
.as_ref()
.and_then(|mem_bio| unsafe {
cvt(ffi::ASN1_GENERALIZEDTIME_print(
mem_bio.as_ptr(),
self.as_ptr(),
))
.ok()?;
str::from_utf8(mem_bio.get_buf()).ok()
})
.unwrap_or("error");
f.write_str(msg)
}
}
@ -528,7 +527,20 @@ impl Asn1BitStringRef {
#[corresponds(ASN1_STRING_get0_data)]
#[must_use]
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.

View File

@ -68,7 +68,10 @@ impl MemBio {
unsafe {
let mut ptr = ptr::null_mut();
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)
}
}
}

View File

@ -51,7 +51,6 @@ impl<'a> Deriver<'a> {
///
/// It can be used to size the buffer passed to [`Deriver::derive`].
#[corresponds(EVP_PKEY_derive)]
/// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
pub fn len(&mut self) -> Result<usize, ErrorStack> {
unsafe {
let mut len = 0;

View File

@ -32,7 +32,7 @@ where
}
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)]
params_to_der,
ffi::i2d_DHparams

View File

@ -15,10 +15,12 @@
//! Err(e) => println!("Parsing Error: {:?}", e),
//! }
//! ```
use libc::{c_char, c_uint};
use libc::{c_char, c_int, c_uint};
use openssl_macros::corresponds;
use std::borrow::Cow;
use std::error;
use std::ffi::CStr;
use std::ffi::CString;
use std::fmt;
use std::io;
use std::ptr;
@ -26,6 +28,8 @@ use std::str;
use crate::ffi;
pub use crate::ffi::ErrLib;
/// Collection of [`Error`]s from OpenSSL.
///
/// [`Error`]: struct.Error.html
@ -34,7 +38,8 @@ pub struct ErrorStack(Vec<Error>);
impl ErrorStack {
/// Pops the contents of the OpenSSL error stack, and returns it.
#[allow(clippy::must_use_candidate)]
#[corresponds(ERR_get_error_line_data)]
#[must_use = "Use ErrorStack::clear() to drop the error stack"]
pub fn get() -> ErrorStack {
let mut vec = vec![];
while let Some(err) = Error::get() {
@ -44,6 +49,7 @@ impl ErrorStack {
}
/// Pushes the errors back onto the OpenSSL error stack.
#[corresponds(ERR_put_error)]
pub fn put(&self) {
for error in self.errors() {
error.put();
@ -53,7 +59,15 @@ impl ErrorStack {
/// Used to report errors from the Rust crate
#[cold]
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()))])
}
/// Empties the current thread's error queue.
#[corresponds(ERR_clear_error)]
pub(crate) fn clear() {
unsafe {
ffi::ERR_clear_error();
}
}
}
@ -80,7 +94,9 @@ impl fmt::Display for ErrorStack {
write!(
fmt,
"[{}]",
err.reason_internal().unwrap_or("unknown reason")
err.reason_internal()
.or_else(|| err.library())
.unwrap_or("unknown reason")
)?;
}
Ok(())
@ -101,13 +117,20 @@ impl From<ErrorStack> for fmt::Error {
}
}
/// An error reported from OpenSSL.
/// A detailed error reported as part of an [`ErrorStack`].
#[derive(Clone)]
pub struct Error {
code: c_uint,
file: *const c_char,
line: c_uint,
data: Option<Cow<'static, str>>,
data: Data,
}
#[derive(Clone)]
enum Data {
None,
CString(CString),
String(String),
}
unsafe impl Sync for Error {}
@ -117,7 +140,8 @@ static BORING_INTERNAL: &CStr = c"boring-rust";
impl Error {
/// Pops the first error off the OpenSSL error stack.
#[allow(clippy::must_use_candidate)]
#[must_use = "Use ErrorStack::clear() to drop the error stack"]
#[corresponds(ERR_get_error_line_data)]
pub fn get() -> Option<Error> {
unsafe {
ffi::init();
@ -132,11 +156,9 @@ impl Error {
// 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
let data = if flags & ffi::ERR_FLAG_STRING != 0 {
let bytes = CStr::from_ptr(data as *const _).to_bytes();
let data = String::from_utf8_lossy(bytes).into_owned();
Some(data.into())
Data::CString(CStr::from_ptr(data.cast()).to_owned())
} else {
None
Data::None
};
Some(Error {
code,
@ -150,6 +172,7 @@ impl Error {
}
/// Pushes the error back onto the OpenSSL error stack.
#[corresponds(ERR_put_error)]
pub fn put(&self) {
unsafe {
ffi::ERR_put_error(
@ -159,28 +182,29 @@ impl Error {
self.file,
self.line,
);
let ptr = match self.data {
Some(Cow::Borrowed(data)) => Some(data.as_ptr() as *mut c_char),
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);
if let Some(cstr) = self.data_cstr() {
ffi::ERR_set_error_data(cstr.as_ptr().cast_mut(), ffi::ERR_FLAG_STRING);
}
}
}
/// Returns the raw OpenSSL error code for this error.
/// 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**.
///
/// Use [`Error::library_code()`] and [`Error::library_reason()`] instead.
/// Packed error codes are different than [SSL error codes](crate::ssl::ErrorCode).
#[must_use]
#[deprecated(note = "use library_reason() to compare error codes")]
pub fn code(&self) -> c_uint {
self.code
}
@ -196,32 +220,24 @@ impl Error {
if cstr.is_null() {
return None;
}
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).ok()
CStr::from_ptr(cstr.cast())
.to_str()
.ok()
.filter(|&msg| msg != "unknown library")
}
}
/// Returns the raw OpenSSL error constant for the library reporting the
/// error.
/// Returns the raw OpenSSL error constant for the library reporting the error (`ERR_LIB_{name}`).
///
/// Error [reason codes](Error::library_reason) are not globally unique, but scoped to each library.
#[must_use]
pub fn library_code(&self) -> libc::c_int {
pub fn library_code(&self) -> c_int {
ffi::ERR_GET_LIB(self.code)
}
/// Returns the name of the function reporting the error.
#[must_use]
/// Returns `None`. Boring doesn't use function codes.
pub fn function(&self) -> Option<&'static str> {
if self.is_internal() {
return None;
}
unsafe {
let cstr = ffi::ERR_func_error_string(self.code);
if cstr.is_null() {
return None;
}
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).ok()
}
None
}
/// Returns the reason for the error.
@ -232,14 +248,19 @@ impl Error {
if cstr.is_null() {
return None;
}
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).ok()
CStr::from_ptr(cstr.cast()).to_str().ok()
}
}
/// Returns the raw OpenSSL error constant for the reason for the error.
/// 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.
/// Use [`Error::library_reason`] to compare error codes.
///
/// 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.
#[must_use]
pub fn reason_code(&self) -> libc::c_int {
pub fn reason_code(&self) -> c_int {
ffi::ERR_GET_REASON(self.code)
}
@ -250,12 +271,15 @@ impl Error {
if self.file.is_null() {
return "";
}
let bytes = CStr::from_ptr(self.file as *const _).to_bytes();
str::from_utf8(bytes).unwrap_or_default()
CStr::from_ptr(self.file.cast())
.to_str()
.unwrap_or_default()
}
}
/// Returns the line in the source file which encountered the error.
///
/// 0 if unknown
#[allow(clippy::unnecessary_cast)]
#[must_use]
pub fn line(&self) -> u32 {
@ -265,15 +289,29 @@ impl Error {
/// Returns additional data describing the error.
#[must_use]
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),
}
}
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(),
};
CString::new(s).ok().map(Cow::Owned)
}
fn new_internal(msg: Data) -> Self {
Self {
code: ffi::ERR_PACK(ffi::ERR_LIB_NONE.0 as _, 0, 0) as _,
file: BORING_INTERNAL.as_ptr(),
line: 0,
data: Some(msg.into()),
data: msg,
}
}
@ -294,20 +332,19 @@ impl Error {
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut builder = fmt.debug_struct("Error");
builder.field("code", &self.code());
if let Some(library) = self.library() {
builder.field("library", &library);
builder.field("code", &self.code);
if !self.is_internal() {
if let Some(library) = self.library() {
builder.field("library", &library);
}
builder.field("library_code", &self.library_code());
if let Some(reason) = self.reason() {
builder.field("reason", &reason);
}
builder.field("reason_code", &self.reason_code());
builder.field("file", &self.file());
builder.field("line", &self.line());
}
builder.field("library_code", &self.library_code());
if let Some(function) = self.function() {
builder.field("function", &function);
}
if let Some(reason) = self.reason() {
builder.field("reason", &reason);
}
builder.field("reason_code", &self.reason_code());
builder.field("file", &self.file());
builder.field("line", &self.line());
if let Some(data) = self.data() {
builder.field("data", &data);
}
@ -321,7 +358,7 @@ impl fmt::Display for Error {
fmt,
"{}\n\nCode: {:08X}\nLoc: {}:{}",
self.reason_internal().unwrap_or("unknown TLS error"),
self.code(),
&self.code,
self.file(),
self.line()
)

View File

@ -88,7 +88,9 @@ impl Nid {
pub fn long_name(&self) -> Result<&'static str, ErrorStack> {
unsafe {
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> {
unsafe {
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)
}
}

View File

@ -413,7 +413,6 @@ impl Rsa<Public> {
/// `n` is the modulus common to both public and private key.
/// `e` is the public exponent.
#[corresponds(RSA_new)]
/// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html
pub fn from_public_components(n: BigNum, e: BigNum) -> Result<Rsa<Public>, ErrorStack> {
unsafe {
let rsa = cvt_p(ffi::RSA_new())?;
@ -472,7 +471,6 @@ impl RsaPrivateKeyBuilder {
/// `n` is the modulus common to both public and private key.
/// `e` is the public exponent and `d` is the private exponent.
#[corresponds(RSA_new)]
/// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html
pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
unsafe {
let rsa = cvt_p(ffi::RSA_new())?;

View File

@ -478,7 +478,7 @@ impl<'a> Verifier<'a> {
match r {
1 => Ok(true),
0 => {
ErrorStack::get(); // discard error stack
ErrorStack::clear(); // discard error stack
Ok(false)
}
_ => Err(ErrorStack::get()),
@ -500,7 +500,7 @@ impl<'a> Verifier<'a> {
match r {
1 => Ok(true),
0 => {
ErrorStack::get();
ErrorStack::clear();
Ok(false)
}
_ => Err(ErrorStack::get()),

View File

@ -11,7 +11,7 @@ use std::pin::Pin;
use std::sync::LazyLock;
use std::task::{ready, Context, Poll, Waker};
/// The type of futures to pass to [`SslContextBuilderExt::set_async_select_certificate_callback`].
/// The type of futures to pass to [`SslContextBuilder::set_async_select_certificate_callback`].
pub type BoxSelectCertFuture = ExDataFuture<Result<BoxSelectCertFinish, AsyncSelectCertError>>;
/// The type of callbacks returned by [`BoxSelectCertFuture`] methods.
@ -25,19 +25,19 @@ pub type BoxPrivateKeyMethodFuture =
pub type BoxPrivateKeyMethodFinish =
Box<dyn FnOnce(&mut SslRef, &mut [u8]) -> Result<usize, AsyncPrivateKeyMethodError>>;
/// The type of futures to pass to [`SslContextBuilderExt::set_async_get_session_callback`].
/// The type of futures to pass to [`SslContextBuilder::set_async_get_session_callback`].
pub type BoxGetSessionFuture = ExDataFuture<Option<BoxGetSessionFinish>>;
/// The type of callbacks returned by [`BoxSelectCertFuture`] methods.
pub type BoxGetSessionFinish = Box<dyn FnOnce(&mut SslRef, &[u8]) -> Option<SslSession>>;
/// The type of futures to pass to [`SslContextBuilderExt::set_async_custom_verify_callback`].
/// The type of futures to pass to [`SslContextBuilder::set_async_custom_verify_callback`].
pub type BoxCustomVerifyFuture = ExDataFuture<Result<BoxCustomVerifyFinish, SslAlert>>;
/// The type of callbacks returned by [`BoxCustomVerifyFuture`] methods.
pub type BoxCustomVerifyFinish = Box<dyn FnOnce(&mut SslRef) -> Result<(), SslAlert>>;
/// Convenience alias for futures stored in [`Ssl`] ex data by [`SslContextBuilderExt`] methods.
/// Convenience alias for futures stored in [`Ssl`] ex data by [`SslContextBuilder`] methods.
///
/// Public for documentation purposes.
pub type ExDataFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
@ -95,7 +95,7 @@ impl SslContextBuilder {
let finish = fut_result.or(Err(SelectCertError::ERROR))?;
finish(client_hello).or(Err(SelectCertError::ERROR))
})
});
}
/// Configures a custom private key method on the context.
@ -123,7 +123,7 @@ impl SslContextBuilder {
///
/// # Safety
///
/// The returned [`SslSession`] must not be associated with a different [`SslContext`].
/// The returned [`SslSession`] must not be associated with a different [`SslContextBuilder`].
pub unsafe fn set_async_get_session_callback<F>(&mut self, callback: F)
where
F: Fn(&mut SslRef, &[u8]) -> Option<BoxGetSessionFuture> + Send + Sync + 'static,
@ -144,7 +144,7 @@ impl SslContextBuilder {
}
};
self.set_get_session_callback(async_callback)
self.set_get_session_callback(async_callback);
}
/// Configures certificate verification.
@ -167,7 +167,7 @@ impl SslContextBuilder {
where
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
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`.

View File

@ -399,7 +399,7 @@ pub(super) unsafe extern "C" fn raw_remove_session<F>(
.ex_data(SslContext::cached_ex_index::<F>())
.expect("BUG: remove session callback missing");
callback(ctx, session)
callback(ctx, session);
}
type DataPtr = *const c_uchar;
@ -451,14 +451,14 @@ where
{
// SAFETY: boring provides valid inputs.
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
.ssl_context()
.ex_data(SslContext::cached_ex_index::<F>())
.expect("BUG: get session callback missing");
callback(ssl, line);
callback(ssl, &line);
}
pub(super) unsafe extern "C" fn raw_sign<M>(

View File

@ -1,16 +1,20 @@
use crate::ffi;
use crate::x509::X509VerifyError;
use libc::c_int;
use openssl_macros::corresponds;
use std::error;
use std::error::Error as StdError;
use std::ffi::CStr;
use std::fmt;
use std::io;
use crate::error::ErrorStack;
use crate::ssl::MidHandshakeSslStream;
/// An error code returned from SSL functions.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
/// `SSL_ERROR_*` error code returned from SSL functions.
///
/// This is different than [packed error codes](crate::error::Error).
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct ErrorCode(c_int);
impl ErrorCode {
@ -50,16 +54,52 @@ impl ErrorCode {
/// An error occurred in the SSL library.
pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL);
/// Wrap an `SSL_ERROR_*` error code.
///
/// This is different than [packed error codes](crate::error::Error).
#[must_use]
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
pub fn from_raw(raw: c_int) -> ErrorCode {
ErrorCode(raw)
let code = ErrorCode(raw);
debug_assert!(
raw < 64 || code.description().is_some(),
"{raw} is not an SSL_ERROR_* code"
);
code
}
/// An `SSL_ERROR_*` error code.
///
/// This is different than [packed error codes](crate::error::Error).
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn as_raw(&self) -> c_int {
self.0
}
#[corresponds(SSL_error_description)]
pub fn description(self) -> Option<&'static str> {
unsafe {
let msg = ffi::SSL_error_description(self.0);
if msg.is_null() {
return None;
}
CStr::from_ptr(msg).to_str().ok()
}
}
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} ({})", self.description().unwrap_or("error"), self.0)
}
}
impl fmt::Debug for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
#[derive(Debug)]
@ -68,7 +108,7 @@ pub(crate) enum InnerError {
Ssl(ErrorStack),
}
/// An SSL error.
/// A general SSL error, based on [`SSL_ERROR_*` error codes](ErrorCode).
#[derive(Debug)]
pub struct Error {
pub(crate) code: ErrorCode,
@ -76,6 +116,7 @@ pub struct Error {
}
impl Error {
/// An `SSL_ERROR_*` error code.
#[must_use]
pub fn code(&self) -> ErrorCode {
self.code
@ -96,6 +137,7 @@ impl Error {
}
}
/// Stack of [library-specific errors](crate::error::Error), if available.
#[must_use]
pub fn ssl_error(&self) -> Option<&ErrorStack> {
match self.cause {
@ -131,26 +173,27 @@ impl From<ErrorStack> for Error {
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.code {
ErrorCode::ZERO_RETURN => fmt.write_str("the SSL session has been shut down"),
let msg = match self.code {
ErrorCode::ZERO_RETURN => "the SSL session has been shut down",
ErrorCode::WANT_READ => match self.io_error() {
Some(_) => fmt.write_str("a nonblocking read call would have blocked"),
None => fmt.write_str("the operation should be retried"),
Some(_) => "a nonblocking read call would have blocked",
None => "the operation should be retried",
},
ErrorCode::WANT_WRITE => match self.io_error() {
Some(_) => fmt.write_str("a nonblocking write call would have blocked"),
None => fmt.write_str("the operation should be retried"),
Some(_) => "a nonblocking write call would have blocked",
None => "the operation should be retried",
},
ErrorCode::SYSCALL => match self.io_error() {
Some(err) => write!(fmt, "{err}"),
None => fmt.write_str("unexpected EOF"),
Some(err) => return err.fmt(fmt),
None => "unexpected EOF",
},
ErrorCode::SSL => match self.ssl_error() {
Some(e) => write!(fmt, "{e}"),
None => fmt.write_str("unknown BoringSSL error"),
Some(err) => return err.fmt(fmt),
None => "unknown BoringSSL error",
},
ErrorCode(code) => write!(fmt, "unknown error code {code}"),
}
ErrorCode(code) => return code.fmt(fmt),
};
fmt.write_str(msg)
}
}

View File

@ -1841,7 +1841,7 @@ impl SslContextBuilder {
+ Sync
+ 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.
@ -2564,7 +2564,7 @@ impl SslCipherRef {
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.
@ -2590,7 +2590,7 @@ impl SslCipherRef {
// SSL_CIPHER_description requires a buffer of at least 128 bytes.
let mut buf = [0; 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()
}
}
@ -3216,6 +3216,8 @@ impl SslRef {
}
/// 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)]
#[must_use]
pub fn state_string(&self) -> &'static str {
@ -3224,10 +3226,12 @@ impl SslRef {
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 empty string if the state wasn't valid UTF-8.
#[corresponds(SSL_state_string_long)]
#[must_use]
pub fn state_string_long(&self) -> &'static str {
@ -3236,7 +3240,7 @@ impl SslRef {
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).
@ -3348,6 +3352,8 @@ impl SslRef {
}
/// 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)]
#[must_use]
pub fn version_str(&self) -> &'static str {
@ -3356,7 +3362,7 @@ impl SslRef {
CStr::from_ptr(ptr as *const _)
};
str::from_utf8(version.to_bytes()).unwrap()
version.to_str().unwrap()
}
/// Sets the minimum supported protocol version.
@ -4028,10 +4034,11 @@ impl<S> MidHandshakeSslStream<S> {
Ok(self.stream)
} else {
self.error = self.stream.make_error(ret);
match self.error.would_block() {
true => Err(HandshakeError::WouldBlock(self)),
false => Err(HandshakeError::Failure(self)),
}
Err(if self.error.would_block() {
HandshakeError::WouldBlock(self)
} else {
HandshakeError::Failure(self)
})
}
}
}
@ -4455,16 +4462,11 @@ where
Ok(stream)
} else {
let error = stream.make_error(ret);
match error.would_block() {
true => Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
stream,
error,
})),
false => Err(HandshakeError::Failure(MidHandshakeSslStream {
stream,
error,
})),
}
Err(if error.would_block() {
HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error })
} else {
HandshakeError::Failure(MidHandshakeSslStream { stream, error })
})
}
}
}

View File

@ -13,6 +13,9 @@ foreign_type_and_impl_send_sync! {
type CType = c_char;
fn drop = free;
/// # Safety
///
/// MUST be UTF-8.
pub struct OpensslString;
}

View File

@ -19,7 +19,6 @@ use std::mem;
use std::net::IpAddr;
use std::path::Path;
use std::ptr;
use std::slice;
use std::str;
use std::sync::{LazyLock, Once};
@ -169,11 +168,10 @@ impl X509StoreContextRef {
/// * `cert_chain` - The certificates chain.
/// * `with_context` - The closure that is called with the initialized context.
///
/// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
/// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
/// Calls [`X509_STORE_CTX_cleanup`] after calling `with_context`.
///
/// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html
/// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html
#[corresponds(X509_STORE_CTX_init)]
pub fn init<F, T>(
&mut self,
trust: &store::X509StoreRef,
@ -789,6 +787,13 @@ impl X509Ref {
}
}
#[corresponds(X509_check_ip_asc)]
pub fn check_ip_asc(&self, address: &str) -> Result<bool, ErrorStack> {
let c_str = CString::new(address).map_err(ErrorStack::internal_error)?;
unsafe { cvt_n(ffi::X509_check_ip_asc(self.as_ptr(), c_str.as_ptr(), 0)).map(|n| n == 1) }
}
to_pem! {
/// Serializes the certificate into a PEM-encoded X509 structure.
///
@ -859,7 +864,7 @@ impl X509 {
if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM.0.try_into().unwrap()
&& ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
{
ffi::ERR_clear_error();
ErrorStack::clear();
break;
}
@ -902,7 +907,7 @@ impl fmt::Debug for X509 {
if let Ok(public_key) = &self.public_key() {
debug_struct.field("public_key", public_key);
};
}
// TODO: Print extensions once they are supported on the X509 struct.
debug_struct.finish()
@ -1371,10 +1376,7 @@ pub struct X509ReqBuilder(X509Req);
impl X509ReqBuilder {
/// Returns a builder for a certificate request.
///
/// This corresponds to [`X509_REQ_new`].
///
///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html
#[corresponds(X509_REQ_new)]
pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
unsafe {
ffi::init();
@ -1383,10 +1385,7 @@ impl X509ReqBuilder {
}
/// Set the numerical value of the version field.
///
/// This corresponds to [`X509_REQ_set_version`].
///
///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html
#[corresponds(X509_REQ_set_version)]
pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
}
@ -1544,10 +1543,7 @@ impl X509ReqRef {
}
/// Returns the public key of the certificate request.
///
/// This corresponds to [`X509_REQ_get_pubkey"]
///
/// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html
#[corresponds(X509_REQ_get_pubkey)]
pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
unsafe {
let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
@ -1558,10 +1554,7 @@ impl X509ReqRef {
/// Check if the certificate request is signed using the given public key.
///
/// Returns `true` if verification succeeds.
///
/// This corresponds to [`X509_REQ_verify"].
///
/// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html
#[corresponds(X509_REQ_verify)]
pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
where
T: HasPublic,
@ -1570,8 +1563,7 @@ impl X509ReqRef {
}
/// Returns the extensions of the certificate request.
///
/// This corresponds to [`X509_REQ_get_extensions"]
#[corresponds(X509_REQ_get_extensions)]
pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
unsafe {
let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
@ -1626,6 +1618,8 @@ impl X509VerifyError {
}
/// 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)]
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
@ -1634,7 +1628,7 @@ impl X509VerifyError {
unsafe {
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()
}
}
}
@ -1786,14 +1780,12 @@ impl GeneralNameRef {
return None;
}
let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ia5 as *mut _);
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ia5 as *mut _);
let asn = Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ia5);
let slice = slice::from_raw_parts(ptr, len as usize);
// IA5Strings are stated to be ASCII (specifically IA5). Hopefully
// OpenSSL checks that when loading a certificate but if not we'll
// use this instead of from_utf8_unchecked just in case.
str::from_utf8(slice).ok()
asn.to_str()
}
}
@ -1823,10 +1815,7 @@ impl GeneralNameRef {
return None;
}
let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ip as *mut _);
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ip as *mut _);
Some(slice::from_raw_parts(ptr, len as usize))
Some(Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ip).as_slice())
}
}
}
@ -1902,8 +1891,8 @@ impl Stackable for X509Object {
use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
use crate::ffi::{
ASN1_STRING_get0_data, X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version,
X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore,
X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version, X509_STORE_CTX_get0_chain,
X509_set1_notAfter, X509_set1_notBefore,
};
use crate::ffi::X509_OBJECT_get0_X509;

View File

@ -836,3 +836,16 @@ fn test_load_subject_der() {
];
X509Name::from_der(SUBJECT_DER).unwrap();
}
#[test]
fn test_check_ip_asc() {
// Covers 127.0.0.1 and 0:0:0:0:0:0:0:1
let cert = include_bytes!("../../../test/alt_name_cert.pem");
let cert = X509::from_pem(cert).unwrap();
assert!(cert.check_ip_asc("127.0.0.1").unwrap());
assert!(!cert.check_ip_asc("127.0.0.2").unwrap());
assert!(cert.check_ip_asc("0:0:0:0:0:0:0:1").unwrap());
assert!(!cert.check_ip_asc("0:0:0:0:0:0:0:2").unwrap());
}

View File

@ -22,7 +22,7 @@ impl<S> AsyncStreamBridge<S> {
}
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