diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index 7f63b2fa..c40f611d 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -36,6 +36,7 @@ pub(crate) struct Env { pub(crate) android_ndk_home: Option, pub(crate) cmake_toolchain_file: Option, pub(crate) cpp_runtime_lib: Option, + pub(crate) docs_rs: bool, } impl Config { @@ -185,6 +186,7 @@ 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"), + docs_rs: var("DOCS_RS").is_some(), } } } diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 326f17e8..413a960f 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -318,8 +318,8 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { ); } _ => { - eprintln!( - "warning: no toolchain file configured by boring-sys for {}", + println!( + "cargo:warning=no toolchain file configured by boring-sys for {}", config.target ); } @@ -339,7 +339,7 @@ fn verify_fips_clang_version() -> (&'static str, &'static str) { let output = match Command::new(tool).arg("--version").output() { Ok(o) => o, Err(e) => { - eprintln!("warning: missing {tool}, trying other compilers: {e}"); + println!("cargo:warning=missing {tool}, trying other compilers: {e}"); // NOTE: hard-codes that the loop below checks the version return None; } @@ -372,8 +372,8 @@ fn verify_fips_clang_version() -> (&'static str, &'static str) { "unsupported clang version \"{cc_version}\": FIPS requires clang {REQUIRED_CLANG_VERSION}" ); } else if !cc_version.is_empty() { - eprintln!( - "warning: FIPS requires clang version {REQUIRED_CLANG_VERSION}, skipping incompatible version \"{cc_version}\"" + println!( + "cargo:warning=FIPS requires clang version {REQUIRED_CLANG_VERSION}, skipping incompatible version \"{cc_version}\"" ); } } @@ -423,9 +423,9 @@ fn get_extra_clang_args_for_bindgen(config: &Config) -> Vec { .unwrap(); if !output.status.success() { if let Some(exit_code) = output.status.code() { - eprintln!("xcrun failed: exit code {exit_code}"); + println!("cargo:warning=xcrun failed: exit code {exit_code}"); } else { - eprintln!("xcrun failed: killed"); + println!("cargo:warning=xcrun failed: killed"); } std::io::stderr().write_all(&output.stderr).unwrap(); // Uh... let's try anyway, I guess? @@ -449,8 +449,8 @@ fn get_extra_clang_args_for_bindgen(config: &Config) -> Vec { let toolchain = match pick_best_android_ndk_toolchain(&android_sysroot) { Ok(toolchain) => toolchain, Err(e) => { - eprintln!( - "warning: failed to find prebuilt Android NDK toolchain for bindgen: {e}" + println!( + "cargo:warning=failed to find prebuilt Android NDK toolchain for bindgen: {e}" ); // Uh... let's try anyway, I guess? return params; @@ -572,8 +572,13 @@ fn built_boring_source_path(config: &Config) -> &PathBuf { let mut cfg = get_boringssl_cmake_config(config); - if let Ok(threads) = std::thread::available_parallelism() { - cfg.env("CMAKE_BUILD_PARALLEL_LEVEL", threads.to_string()); + let num_jobs = std::env::var("NUM_JOBS").ok().or_else(|| { + std::thread::available_parallelism() + .ok() + .map(|t| t.to_string()) + }); + if let Some(num_jobs) = num_jobs { + cfg.env("CMAKE_BUILD_PARALLEL_LEVEL", num_jobs); } if config.features.fips { @@ -655,8 +660,15 @@ fn get_cpp_runtime_lib(config: &Config) -> Option { fn main() { let config = Config::from_env(); - let bssl_dir = built_boring_source_path(&config); - let build_path = get_boringssl_platform_output_path(&config); + if !config.env.docs_rs { + emit_link_directives(&config); + } + generate_bindings(&config); +} + +fn emit_link_directives(config: &Config) { + let bssl_dir = built_boring_source_path(config); + let build_path = get_boringssl_platform_output_path(config); if config.is_bazel || (config.features.is_fips_like() && config.env.path.is_some()) { println!( @@ -688,10 +700,10 @@ fn main() { } if config.features.fips_link_precompiled { - link_in_precompiled_bcm_o(&config); + 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=static=crypto"); @@ -701,13 +713,15 @@ fn main() { // Rust 1.87.0 compat - https://github.com/rust-lang/rust/pull/138233 println!("cargo:rustc-link-lib=advapi32"); } +} +fn generate_bindings(config: &Config) { let include_path = config.env.include_path.clone().unwrap_or_else(|| { if let Some(bssl_path) = &config.env.path { return bssl_path.join("include"); } - let src_path = get_boringssl_source_path(&config); + let src_path = get_boringssl_source_path(config); let candidate = src_path.join("include"); if candidate.exists() { @@ -741,7 +755,7 @@ fn main() { .layout_tests(supports_layout_tests) .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)) + .clang_args(get_extra_clang_args_for_bindgen(config)) .clang_arg("-I") .clang_arg(include_path.display().to_string()); diff --git a/boring/src/pkey.rs b/boring/src/pkey.rs index f1896756..e737c333 100644 --- a/boring/src/pkey.rs +++ b/boring/src/pkey.rs @@ -56,7 +56,7 @@ use crate::ec::EcKey; use crate::error::ErrorStack; use crate::rsa::Rsa; use crate::util::{invoke_passwd_cb, CallbackState}; -use crate::{cvt, cvt_p}; +use crate::{cvt, cvt_0i, cvt_p}; /// A tag type indicating that a key only has parameters. pub enum Params {} @@ -228,6 +228,36 @@ where { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } + + /// Returns the length of the "raw" form of the public key. Only supported for certain key types. + #[corresponds(EVP_PKEY_get_raw_public_key)] + pub fn raw_public_key_len(&self) -> Result { + unsafe { + let mut size = 0; + _ = cvt_0i(ffi::EVP_PKEY_get_raw_public_key( + self.as_ptr(), + std::ptr::null_mut(), + &mut size, + ))?; + Ok(size) + } + } + + /// Outputs a copy of the "raw" form of the public key. Only supported for certain key types. + /// + /// Returns the used portion of `out`. + #[corresponds(EVP_PKEY_get_raw_public_key)] + pub fn raw_public_key<'a>(&self, out: &'a mut [u8]) -> Result<&'a [u8], ErrorStack> { + unsafe { + let mut size = out.len(); + _ = cvt_0i(ffi::EVP_PKEY_get_raw_public_key( + self.as_ptr(), + out.as_mut_ptr(), + &mut size, + ))?; + Ok(&out[..size]) + } + } } impl PKeyRef @@ -266,6 +296,36 @@ where private_key_to_der_pkcs8_passphrase, ffi::i2d_PKCS8PrivateKey_bio } + + /// Returns the length of the "raw" form of the private key. Only supported for certain key types. + #[corresponds(EVP_PKEY_get_raw_private_key)] + pub fn raw_private_key_len(&self) -> Result { + unsafe { + let mut size = 0; + _ = cvt_0i(ffi::EVP_PKEY_get_raw_private_key( + self.as_ptr(), + std::ptr::null_mut(), + &mut size, + ))?; + Ok(size) + } + } + + /// Outputs a copy of the "raw" form of the private key. Only supported for certain key types. + /// + /// Returns the used portion of `out`. + #[corresponds(EVP_PKEY_get_raw_private_key)] + pub fn raw_private_key<'a>(&self, out: &'a mut [u8]) -> Result<&'a [u8], ErrorStack> { + unsafe { + let mut size = out.len(); + _ = cvt_0i(ffi::EVP_PKEY_get_raw_private_key( + self.as_ptr(), + out.as_mut_ptr(), + &mut size, + ))?; + Ok(&out[..size]) + } + } } impl fmt::Debug for PKey { @@ -451,6 +511,8 @@ use crate::ffi::EVP_PKEY_up_ref; #[cfg(test)] mod tests { + use hex::FromHex as _; + use crate::ec::EcKey; use crate::nid::Nid; use crate::rsa::Rsa; @@ -561,4 +623,34 @@ mod tests { assert_eq!(pkey.id(), Id::EC); assert!(pkey.rsa().is_err()); } + + #[test] + fn test_raw_accessors() { + const ED25519_PRIVATE_KEY_DER: &str = concat!( + "302e020100300506032b6570042204207c8c6497f9960d5595d7815f550569e5", + "f77764ac97e63e339aaa68cc1512b683" + ); + let pkey = + PKey::private_key_from_der(&Vec::from_hex(ED25519_PRIVATE_KEY_DER).unwrap()).unwrap(); + assert_eq!(pkey.id(), Id::ED25519); + + let priv_len = pkey.raw_private_key_len().unwrap(); + assert_eq!(priv_len, 32); + let mut raw_private_key_buf = [0; 40]; + let raw_private_key = pkey.raw_private_key(&mut raw_private_key_buf).unwrap(); + assert_eq!(raw_private_key.len(), 32); + assert_ne!(raw_private_key, [0; 32]); + pkey.raw_private_key(&mut [0; 5]) + .expect_err("buffer too small"); + + let pub_len = pkey.raw_public_key_len().unwrap(); + assert_eq!(pub_len, 32); + let mut raw_public_key_buf = [0; 40]; + let raw_public_key = pkey.raw_public_key(&mut raw_public_key_buf).unwrap(); + assert_eq!(raw_public_key.len(), 32); + assert_ne!(raw_public_key, [0; 32]); + assert_ne!(raw_public_key, raw_private_key); + pkey.raw_public_key(&mut [0; 5]) + .expect_err("buffer too small"); + } }