diff --git a/rustls-wolfcrypt-provider/src/hmac/mod.rs b/rustls-wolfcrypt-provider/src/hmac/mod.rs index 1092fa8..4f8cc85 100644 --- a/rustls-wolfcrypt-provider/src/hmac/mod.rs +++ b/rustls-wolfcrypt-provider/src/hmac/mod.rs @@ -21,23 +21,23 @@ impl WCShaHmac { fn algorithm(&self) -> i32 { match self { - WCShaHmac::Sha256 => WC_SHA256.try_into().unwrap(), - WCShaHmac::Sha384 => WC_SHA384.try_into().unwrap(), + WCShaHmac::Sha256 => wc_HashType_WC_HASH_TYPE_SHA256.try_into().unwrap(), + WCShaHmac::Sha384 => wc_HashType_WC_HASH_TYPE_SHA384.try_into().unwrap(), } } pub fn new(hash_type: wc_HashType) -> Self { match hash_type { - WC_SHA256 => WCShaHmac::Sha256, - WC_SHA384 => WCShaHmac::Sha384, + wolfcrypt_rs::wc_HashType_WC_HASH_TYPE_SHA256 => WCShaHmac::Sha256, + wolfcrypt_rs::wc_HashType_WC_HASH_TYPE_SHA384 => WCShaHmac::Sha384, _ => panic!("Unsupported hash type"), } } pub fn hash_type(&self) -> wc_HashType { match self { - WCShaHmac::Sha256 => WC_SHA256, - WCShaHmac::Sha384 => WC_SHA384, + WCShaHmac::Sha256 => wc_HashType_WC_HASH_TYPE_SHA256, + WCShaHmac::Sha384 => wc_HashType_WC_HASH_TYPE_SHA384, } } diff --git a/rustls-wolfcrypt-provider/src/kx/sec256r1.rs b/rustls-wolfcrypt-provider/src/kx/sec256r1.rs index 426362f..f5dfd6c 100644 --- a/rustls-wolfcrypt-provider/src/kx/sec256r1.rs +++ b/rustls-wolfcrypt-provider/src/kx/sec256r1.rs @@ -35,7 +35,7 @@ impl KeyExchangeSecP256r1 { key_object.init(); rng_object.init(); - let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_id_ECC_SECP256R1) }; + let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_ids_ECC_SECP256R1) }; let mut priv_key_raw = [0u8; 32]; let mut priv_key_raw_len: word32 = priv_key_raw.len() as word32; @@ -45,7 +45,7 @@ impl KeyExchangeSecP256r1 { rng_object.as_ptr(), key_size, key_object.as_ptr(), - ecc_curve_id_ECC_SECP256R1, + ecc_curve_ids_ECC_SECP256R1, ) }; check_if_zero(ret) @@ -112,7 +112,7 @@ impl KeyExchangeSecP256r1 { ptr::null_mut(), 0, priv_key_object.as_ptr(), - ecc_curve_id_ECC_SECP256R1, + ecc_curve_ids_ECC_SECP256R1, ) }; check_if_zero(ret) @@ -124,7 +124,7 @@ impl KeyExchangeSecP256r1 { peer_pub_key[1..33].as_ptr(), peer_pub_key[33..].as_ptr(), ptr::null_mut(), - ecc_curve_id_ECC_SECP256R1, + ecc_curve_ids_ECC_SECP256R1, ) }; check_if_zero(ret) diff --git a/rustls-wolfcrypt-provider/src/kx/sec384r1.rs b/rustls-wolfcrypt-provider/src/kx/sec384r1.rs index 36e4ce5..4754101 100644 --- a/rustls-wolfcrypt-provider/src/kx/sec384r1.rs +++ b/rustls-wolfcrypt-provider/src/kx/sec384r1.rs @@ -37,14 +37,14 @@ impl KeyExchangeSecP384r1 { rng_object.init(); - let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_id_ECC_SECP384R1) }; + let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_ids_ECC_SECP384R1) }; ret = unsafe { wc_ecc_make_key_ex( rng_object.as_ptr(), key_size, key_object.as_ptr(), - ecc_curve_id_ECC_SECP384R1, + ecc_curve_ids_ECC_SECP384R1, ) }; check_if_zero(ret) @@ -115,7 +115,7 @@ impl KeyExchangeSecP384r1 { ptr::null_mut(), 0, priv_key_object.as_ptr(), - ecc_curve_id_ECC_SECP384R1, + ecc_curve_ids_ECC_SECP384R1, ) }; check_if_zero(ret) @@ -131,7 +131,7 @@ impl KeyExchangeSecP384r1 { peer_pub_key[1..49].as_ptr(), peer_pub_key[49..].as_ptr(), ptr::null_mut(), - ecc_curve_id_ECC_SECP384R1, + ecc_curve_ids_ECC_SECP384R1, ) }; check_if_zero(ret) diff --git a/rustls-wolfcrypt-provider/src/kx/sec521r1.rs b/rustls-wolfcrypt-provider/src/kx/sec521r1.rs index 2086581..1887f5d 100644 --- a/rustls-wolfcrypt-provider/src/kx/sec521r1.rs +++ b/rustls-wolfcrypt-provider/src/kx/sec521r1.rs @@ -38,14 +38,14 @@ impl KeyExchangeSecP521r1 { // We initiliaze the rng object. rng_object.init(); - let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_id_ECC_SECP521R1) }; + let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_ids_ECC_SECP521R1) }; ret = unsafe { wc_ecc_make_key_ex( rng_object.as_ptr(), key_size, key_object.as_ptr(), - ecc_curve_id_ECC_SECP521R1, + ecc_curve_ids_ECC_SECP521R1, ) }; check_if_zero(ret) @@ -116,7 +116,7 @@ impl KeyExchangeSecP521r1 { ptr::null_mut(), 0, priv_key_object.as_ptr(), - ecc_curve_id_ECC_SECP521R1, + ecc_curve_ids_ECC_SECP521R1, ) }; check_if_zero(ret) @@ -132,7 +132,7 @@ impl KeyExchangeSecP521r1 { peer_pub_key[1..67].as_ptr(), peer_pub_key[67..].as_ptr(), ptr::null_mut(), - ecc_curve_id_ECC_SECP521R1, + ecc_curve_ids_ECC_SECP521R1, ) }; check_if_zero(ret) diff --git a/rustls-wolfcrypt-provider/src/kx/x25519.rs b/rustls-wolfcrypt-provider/src/kx/x25519.rs index 705be61..685cf6c 100644 --- a/rustls-wolfcrypt-provider/src/kx/x25519.rs +++ b/rustls-wolfcrypt-provider/src/kx/x25519.rs @@ -116,6 +116,21 @@ impl KeyExchangeX25519 { rustls::Error::General("Failed to import Curve25519 private key".into()) })?; + // When wolfSSL is built with curve25519 blinding (pure-C builds, e.g. + // Apple Silicon where no asm backend is selected), the shared-secret + // scalar multiplication draws random values to blind the private + // scalar. An imported key has no RNG attached, so we must supply one; + // otherwise wc_curve25519_shared_secret_ex returns BAD_FUNC_ARG (-173). + // On non-blinding (asm) builds curve25519_set_rng is a no-op. + let mut rng: WC_RNG = unsafe { mem::zeroed() }; + let rng_object = WCRngObject::new(&mut rng); + rng_object.init(); + + ret = unsafe { curve25519_set_rng(private_key_object.as_ptr(), rng_object.as_ptr()) }; + check_if_zero(ret).map_err(|_| { + rustls::Error::General("Failed to set RNG on Curve25519 private key".into()) + })?; + // This function computes a shared secret key given a secret private key and // a received public key. Stores the generated secret in the buffer out. ret = unsafe { @@ -128,7 +143,9 @@ impl KeyExchangeX25519 { ) }; check_if_zero(ret).map_err(|_| { - rustls::Error::General("Failed to compute Curve25519 shared secret".into()) + rustls::Error::General(alloc::format!( + "Failed to compute Curve25519 shared secret (ret = {ret})" + )) })?; Ok(Box::new(out)) diff --git a/rustls-wolfcrypt-provider/src/sign/ecdsa.rs b/rustls-wolfcrypt-provider/src/sign/ecdsa.rs index f747bd8..9e4f612 100644 --- a/rustls-wolfcrypt-provider/src/sign/ecdsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/ecdsa.rs @@ -243,12 +243,12 @@ fn hash_message_for_scheme( } } -/// Converts a rustls `SignatureScheme` to the WolfSSL curve id (ecc_curve_id_ECC_...). +/// Converts a rustls `SignatureScheme` to the WolfSSL curve id (ecc_curve_ids_ECC_...). fn scheme_to_curve_id(scheme: SignatureScheme) -> Result { match scheme { - SignatureScheme::ECDSA_NISTP256_SHA256 => Ok(ecc_curve_id_ECC_SECP256R1), - SignatureScheme::ECDSA_NISTP384_SHA384 => Ok(ecc_curve_id_ECC_SECP384R1), - SignatureScheme::ECDSA_NISTP521_SHA512 => Ok(ecc_curve_id_ECC_SECP521R1), + SignatureScheme::ECDSA_NISTP256_SHA256 => Ok(ecc_curve_ids_ECC_SECP256R1), + SignatureScheme::ECDSA_NISTP384_SHA384 => Ok(ecc_curve_ids_ECC_SECP384R1), + SignatureScheme::ECDSA_NISTP521_SHA512 => Ok(ecc_curve_ids_ECC_SECP521R1), _ => Err("Not an ECDSA_NISTPxxx_SHAxxx scheme"), } } diff --git a/rustls-wolfcrypt-provider/src/sign/eddsa.rs b/rustls-wolfcrypt-provider/src/sign/eddsa.rs index fa07a8f..42478b1 100644 --- a/rustls-wolfcrypt-provider/src/sign/eddsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/eddsa.rs @@ -33,81 +33,73 @@ impl fmt::Debug for Ed25519PrivateKey { impl Ed25519PrivateKey { /// Extract ED25519 private and if available public key values from a PKCS#8 DER formatted key fn extract_key_pair(input_key: &[u8]) -> Result<([u8; 32], Option<[u8; 32]>), rustls::Error> { - let mut public_key_raw: [u8; 32] = [0; ED25519_PUB_KEY_SIZE as usize]; let mut private_key_raw: [u8; 32] = [0; ED25519_KEY_SIZE as usize]; - let mut skip_bytes: usize; - let mut key_sub_slice = input_key; - - const SHORT_FORM_LEN_MAX: u8 = 127; - const TAG_SEQUENCE: u8 = 0x30; - const TAG_OCTET_SEQUENCE: u8 = 0x04; - const TAG_OPTIONAL_SET_OF_ATTRIBUTES: u8 = 0x80; //Implicit, context-specific, and primitive underlying type (SET OF) - const TAG_OPTIONAL_PUBLIC_KEY_BIT_STRING: u8 = 0x81; //Implicit, context-specific, and primitive underlying type (BIT STRING) - - // The input key is encoded in PKCS#8 DER format with a structure as in - // https://www.rfc-editor.org/rfc/rfc5958.html + let mut private_key_raw_len: word32 = private_key_raw.len() as word32; + // Scratch buffer for the optional embedded public key. DecodeAsymKey + // reports it either as the bare 32-byte key, or as the raw DER BIT STRING + // body (a leading 0x00 "unused bits" octet + the 32-byte key = 33 bytes), + // so 33 bytes is the largest form we ever need to hold here. + let mut public_key_scratch: [u8; ED25519_PUB_KEY_SIZE as usize + 1] = + [0; ED25519_PUB_KEY_SIZE as usize + 1]; + let mut public_key_scratch_len: word32 = public_key_scratch.len() as word32; + let mut idx: word32 = 0; + + // Parse the PKCS#8 structure with wolfSSL's own ASN parser. This is the + // same parser wc_Ed25519PrivateKeyDecode uses internally, but calling it + // directly lets us normalise the embedded public key before it is imported. // - // AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey - - // OneAsymmetricKey ::= SEQUENCE { - // version Version, - // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - // privateKey PrivateKey, - // attributes [0] Attributes OPTIONAL, - // ..., - // [[2: publicKey [1] PublicKey OPTIONAL ]], - // ... - // } - - // The key structure must begin with a SEQUENCE tag with at least 2 bytes length if short - // length format is used - if key_sub_slice[0] != TAG_SEQUENCE || key_sub_slice.len() < 2 { - return Err(rustls::Error::General( - "Faulty PKCS#8 ED25519 private key structure".into(), - )); - } - // Check which length format and skip tag and length encoding bytes - if key_sub_slice[1] > SHORT_FORM_LEN_MAX { - skip_bytes = (2 + (key_sub_slice[1] & 0x7F)) as usize; - } else { - skip_bytes = 2; - } - - // Skip version (3 bytes), algorithm ID sequence (0x30 + length encoding bytes + 5 ID bytes), - skip_bytes += 3 + 7; - key_sub_slice = input_key.get(skip_bytes..).unwrap(); - - // Check if next bytes are 0x04, 0x22, 0x04, 0x20 - if !matches!( - key_sub_slice, - [TAG_OCTET_SEQUENCE, 0x22, TAG_OCTET_SEQUENCE, 0x20, ..] - ) { - return Err(rustls::Error::General( - "Faulty PKCS#8 ED25519 private key structure".into(), - )); - } - - // Copy private key value - skip_bytes += 4; - key_sub_slice = input_key.get(skip_bytes..).unwrap(); - private_key_raw.copy_from_slice(&key_sub_slice[..ED25519_KEY_SIZE as usize]); - skip_bytes += ED25519_KEY_SIZE as usize; - key_sub_slice = input_key.get(skip_bytes..).unwrap(); - - // Check if optional SET OF attributes exists and skip - if key_sub_slice.first() == Some(&TAG_OPTIONAL_SET_OF_ATTRIBUTES) { - skip_bytes += (2 + (key_sub_slice[1])) as usize; - key_sub_slice = input_key.get(skip_bytes..).unwrap(); - } + // For an RFC 5958 (PKCS#8 v2) key that carries the optional public key, + // DecodeAsymKey hands back the [1] field as the raw DER BIT STRING body: + // a leading "unused bits" 0x00 octet followed by the 32-byte key (33 bytes + // total). wc_Ed25519PrivateKeyDecode passes that body verbatim to + // wc_ed25519_import_public_ex, which expects the key material itself, + // which is a bare 32-byte key (or a 0x40-prefixed 33-byte form). + // The 0x00-led 33-byte body matches neither, so it is rejected + // with BAD_FUNC_ARG (-173). So we strip the 0x00 octet here and + // hand on the bare 32-byte key instead. + let ret = unsafe { + DecodeAsymKey( + input_key.as_ptr(), + &mut idx, + input_key.len() as word32, + private_key_raw.as_mut_ptr(), + &mut private_key_raw_len, + public_key_scratch.as_mut_ptr(), + &mut public_key_scratch_len, + Key_Sum_ED25519k as i32, + ) + }; + check_if_zero(ret) + .map_err(|_| rustls::Error::General("DecodeAsymKey (ED25519) failed".into()))?; + + // Normalise the optional public key based on the length the parser reported. + let pub_key: Option<[u8; 32]> = match public_key_scratch_len { + // No embedded public key; the caller derives it from the private seed. + 0 => None, + // Bare 32-byte public key. + len if len == ED25519_PUB_KEY_SIZE => Some( + public_key_scratch[..ED25519_PUB_KEY_SIZE as usize] + .try_into() + .map_err(|_| { + rustls::Error::General("Unexpected ED25519 public key encoding".into()) + })?, + ), + // BIT STRING body: leading 0x00 "unused bits" octet + 32-byte key. + len if len == ED25519_PUB_KEY_SIZE + 1 && public_key_scratch[0] == 0x00 => Some( + public_key_scratch[1..1 + ED25519_PUB_KEY_SIZE as usize] + .try_into() + .map_err(|_| { + rustls::Error::General("Unexpected ED25519 public key encoding".into()) + })?, + ), + _ => { + return Err(rustls::Error::General( + "Unexpected ED25519 public key encoding".into(), + )) + } + }; - // Check if optional public key value exists. If exists, skip tag, length encoding byte, - // and bits-used byte - if key_sub_slice.first() == Some(&TAG_OPTIONAL_PUBLIC_KEY_BIT_STRING) { - public_key_raw.copy_from_slice(&key_sub_slice[3..(3 + ED25519_KEY_SIZE as usize)]); - Ok((private_key_raw, Some(public_key_raw))) - } else { - Ok((private_key_raw, None)) - } + Ok((private_key_raw, pub_key)) } } diff --git a/rustls-wolfcrypt-provider/src/sign/rsa.rs b/rustls-wolfcrypt-provider/src/sign/rsa.rs index 0c75790..40dcfba 100644 --- a/rustls-wolfcrypt-provider/src/sign/rsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/rsa.rs @@ -271,7 +271,7 @@ impl Signer for RsaSigner { message.len() as u32, sig_buf.as_mut_ptr(), &mut sig_len, - rsa_key.as_ptr() as *const core::ffi::c_void, + rsa_key.as_ptr() as *mut core::ffi::c_void, mem::size_of_val(&deref_rsa_key_c_type).try_into().unwrap(), rng_object.as_ptr(), ) diff --git a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs index 78065f2..416431f 100644 --- a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs @@ -70,17 +70,17 @@ impl SignatureVerificationAlgorithm for EcdsaVerifier { // Determine curve, how many bytes to skip from public_key, and which hash to use let (curve_id, skip_len, wc_hash_type) = match self.scheme { SignatureScheme::ECDSA_NISTP256_SHA256 => ( - ecc_curve_id_ECC_SECP256R1, + ecc_curve_ids_ECC_SECP256R1, 32, wc_HashType_WC_HASH_TYPE_SHA256, ), SignatureScheme::ECDSA_NISTP384_SHA384 => ( - ecc_curve_id_ECC_SECP384R1, + ecc_curve_ids_ECC_SECP384R1, 48, wc_HashType_WC_HASH_TYPE_SHA384, ), SignatureScheme::ECDSA_NISTP521_SHA512 => ( - ecc_curve_id_ECC_SECP521R1, + ecc_curve_ids_ECC_SECP521R1, 66, wc_HashType_WC_HASH_TYPE_SHA512, ), diff --git a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs index 3b5d7b3..da5d770 100644 --- a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs +++ b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs @@ -62,7 +62,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha256Verify { message.len() as word32, signature.as_ptr(), signature.len() as word32, - rsa_key_object.as_ptr() as *const c_void, + rsa_key_object.as_ptr() as *mut c_void, mem::size_of_val(&derefenced_rsa_key_c_type) .try_into() .unwrap(), @@ -128,7 +128,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha384Verify { message.len() as word32, signature.as_ptr(), signature.len() as word32, - rsa_key_object.as_ptr() as *const c_void, + rsa_key_object.as_ptr() as *mut c_void, mem::size_of_val(&dereferenced_rsa_key_c_type) .try_into() .unwrap(), @@ -194,7 +194,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha512Verify { message.len() as word32, signature.as_ptr(), signature.len() as word32, - rsa_key_object.as_ptr() as *const c_void, + rsa_key_object.as_ptr() as *mut c_void, mem::size_of_val(&dereferenced_rsa_key_c_type) .try_into() .unwrap(), diff --git a/rustls-wolfcrypt-provider/tests/e2e.rs b/rustls-wolfcrypt-provider/tests/e2e.rs index ba58b3e..6044fa9 100644 --- a/rustls-wolfcrypt-provider/tests/e2e.rs +++ b/rustls-wolfcrypt-provider/tests/e2e.rs @@ -59,10 +59,10 @@ fn init_thread_pool() { * Starts background job for wolfssl server (localhost:4443). * */ fn start_wolfssl_server(current_dir_string: String, tls_version: &str) -> Child { - if let Err(e) = env::set_current_dir("../wolfcrypt-rs/wolfssl-5.7.6-stable/") { + if let Err(e) = env::set_current_dir("../wolfcrypt-rs/wolfssl-5.9.1-stable/") { panic!("Error changing directory: {}", e); } else { - println!("Changed directory to wolfssl-5.7.6-stable."); + println!("Changed directory to wolfssl-5.9.1-stable."); Command::new("./examples/server/server") .arg("-d") @@ -410,17 +410,17 @@ mod tests { let test_configs = [ ( SignatureScheme::ECDSA_NISTP256_SHA256, - ecc_curve_id_ECC_SECP256R1, + ecc_curve_ids_ECC_SECP256R1, 32, // P256 key size ), ( SignatureScheme::ECDSA_NISTP384_SHA384, - ecc_curve_id_ECC_SECP384R1, + ecc_curve_ids_ECC_SECP384R1, 48, // P384 key size ), ( SignatureScheme::ECDSA_NISTP521_SHA512, - ecc_curve_id_ECC_SECP521R1, + ecc_curve_ids_ECC_SECP521R1, 66, // P521 key size ), ]; diff --git a/wolfcrypt-rs/build.rs b/wolfcrypt-rs/build.rs index 0a49813..1330a07 100644 --- a/wolfcrypt-rs/build.rs +++ b/wolfcrypt-rs/build.rs @@ -8,10 +8,10 @@ use std::path::PathBuf; use std::process::Command; /// Version-related constants for WolfSSL -const WOLFSSL_DIR: &str = "wolfssl-5.7.6-stable"; -const WOLFSSL_ZIP: &str = "wolfssl-5.7.6-stable.zip"; -const WOLFSSL_URL: &str = "https://github.com/wolfSSL/wolfssl/archive/refs/tags/v5.7.6-stable.zip"; -const WOLFSSL_SHA256: &str = "1aeb6e49222bb9d8cf012063f0dfc3f229084f24ce2b5740a2dcdb64d72b00bf"; +const WOLFSSL_DIR: &str = "wolfssl-5.9.1-stable"; +const WOLFSSL_ZIP: &str = "wolfssl-5.9.1-stable.zip"; +const WOLFSSL_URL: &str = "https://github.com/wolfSSL/wolfssl/archive/refs/tags/v5.9.1-stable.zip"; +const WOLFSSL_SHA256: &str = "a91ccbf742391db95d5f1821273c59841f54a5306b9d2caea0cd7a8f2fbe0a5c"; /// Entry point for the build script. /// Handles the main build process and exits with an error code if anything fails. @@ -72,9 +72,23 @@ fn generate_bindings() -> Result<()> { .map_err(|_| io::Error::other("Failed to generate bindings"))?; let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let bindings_file = out_path.join("bindings.rs"); bindings - .write_to_file(out_path.join("bindings.rs")) - .map_err(|e| io::Error::other(format!("Couldn't write bindings: {e}"))) + .write_to_file(&bindings_file) + .map_err(|e| io::Error::other(format!("Couldn't write bindings: {e}")))?; + + // wolfSSL only compiles wc_curve25519_set_rng when it builds the blinded, + // pure-C curve25519 implementation (WOLFSSL_CURVE25519_BLINDING, i.e. no asm + // backend). Detect it from the generated bindings and expose a cfg so the + // crate can pick the real call vs. a no-op. Declaring it with check-cfg + // keeps `-D warnings` (clippy) builds from failing on an unexpected cfg. + println!("cargo:rustc-check-cfg=cfg(curve25519_blinding)"); + let generated = fs::read_to_string(&bindings_file)?; + if generated.contains("wc_curve25519_set_rng") { + println!("cargo:rustc-cfg=curve25519_blinding"); + } + + Ok(()) } /// Coordinates the complete setup process for WolfSSL. @@ -198,7 +212,6 @@ fn build_wolfssl() -> Result<()> { run_command( "./configure", &[ - "--enable-all", "--enable-all-crypto", "--enable-debug", "--disable-shared", diff --git a/wolfcrypt-rs/src/lib.rs b/wolfcrypt-rs/src/lib.rs index ca6f032..f538270 100644 --- a/wolfcrypt-rs/src/lib.rs +++ b/wolfcrypt-rs/src/lib.rs @@ -1,6 +1,30 @@ pub mod bindings; pub use bindings::*; +/// Attach an RNG to a curve25519 key so the blinded scalar multiplication has +/// entropy. wolfSSL only compiles wc_curve25519_set_rng when it builds the +/// blinded, pure-C curve25519 implementation (WOLFSSL_CURVE25519_BLINDING, +/// i.e. no asm backend). On asm builds the symbol is absent and blinding isn't +/// used, so this becomes a no-op. The curve25519_blinding cfg is emitted by +/// build.rs based on whether that symbol appears in the generated bindings. +/// +/// # Safety +/// key must point to an initialized curve25519_key, and rng to an +/// initialized WC_RNG that outlives the following shared-secret call. +#[cfg(curve25519_blinding)] +pub unsafe fn curve25519_set_rng(key: *mut curve25519_key, rng: *mut WC_RNG) -> i32 { + wc_curve25519_set_rng(key, rng) +} + +/// No-op variant: builds without curve25519 blinding don't attach an RNG. +/// +/// # Safety +/// Same contract as the blinding variant; the arguments are ignored. +#[cfg(not(curve25519_blinding))] +pub unsafe fn curve25519_set_rng(_key: *mut curve25519_key, _rng: *mut WC_RNG) -> i32 { + 0 +} + #[cfg(test)] mod tests { use super::*;