//! # ccc-crypto-wolfssl //! //! wolfSSL / wolfCrypt implementation of the [`ccc_crypto_core::CryptoProvider`] //! trait. This crate builds wolfSSL from source (vendored git submodule) and //! wraps the C functions in safe Rust using FFI bindings generated by bindgen. //! //! ## Usage //! //! Call [`init()`] once at application start (from the bridge crate's //! `ccc_init()` function). That registers a [`WolfSslProvider`] into the //! global [`ProviderRegistry`][ccc_crypto_core::registry::ProviderRegistry]. pub mod aead; pub mod capabilities; pub mod hash; pub mod kdf; pub mod kem; pub mod mac; pub mod provider; // FFI bindings generated by bindgen in build.rs. // When wolfSSL headers are not present (e.g. docs.rs), use a stub. #[allow(non_camel_case_types, non_snake_case, non_upper_case_globals, dead_code, clippy::all)] mod sys { // ── Manual ABI-critical type definitions ──────────────────────────────── // // `ECPoint` contains `ALIGN16 byte point[32]` in the wolfCrypt C headers. // bindgen does not propagate `__attribute__((aligned(16)))` from a struct // *field* to the generated Rust type; it emits a plain 33-byte struct. // wolfCrypt's actual ECPoint is 48 bytes (32 + 1 + 15-byte tail-padding) // with 16-byte alignment. Without the correct size/alignment, every // field that follows ECPoint in `curve25519_key` (including `k` and the // `pubSet`/`privSet` bitfields) lands at the wrong offset relative to the // compiled C library, causing `wc_curve25519_shared_secret_ex` to return // `ECC_BAD_ARG_E` (-170) because it reads `pubSet`/`privSet` from the // wrong memory location. // // We blocklist ECPoint in build.rs so bindgen does not emit it, then // define it here (before the `include!`) with the correct alignment. // The struct is used only as a field inside `curve25519_key`; we never // manipulate its internals directly from Rust. #[repr(C, align(16))] #[derive(Copy, Clone)] pub struct ECPoint { /// u-coordinate of the Curve25519 public key (little-endian). pub point: [u8; 32], /// Length tag used internally by wolfCrypt; always 32 for Curve25519. pub pointSz: u8, // 15 bytes of implicit tail-padding inserted by Rust to satisfy // align(16), matching the C compiler's layout exactly. } // In a real build this pulls in the bindgen-generated file. // The `include!` macro resolves at compile time to the OUT_DIR path. // We guard it behind a cfg so the module still compiles without headers. #[cfg(not(feature = "stub_ffi"))] include!(concat!(env!("OUT_DIR"), "/wolfcrypt_bindings.rs")); // Stub module for environments without the wolfSSL C library. #[cfg(feature = "stub_ffi")] pub use self::stubs::*; #[cfg(feature = "stub_ffi")] pub mod stubs { //! Compile-time stubs for all wolfCrypt C types and functions used in //! this crate. These allow `cargo check --features stub_ffi` to succeed //! without the wolfSSL shared library or headers being present. //! //! **None of these functions will ever be called** — the `stub_ffi` //! feature is only used for type-checking and documentation builds. #![allow(non_camel_case_types, dead_code, unused_variables)] use std::os::raw::{c_int, c_uchar, c_uint, c_void}; // ── Opaque C struct stubs ──────────────────────────────────────────── /// Stub for wolfCrypt `Aes` struct. #[repr(C)] pub struct Aes([u8; 512]); /// Stub for wolfCrypt `Hmac` struct. #[repr(C)] pub struct Hmac([u8; 512]); /// Stub for wolfCrypt `WC_RNG` struct. #[repr(C)] pub struct WC_RNG([u8; 256]); /// Stub for wolfCrypt `wc_Sha512` struct (also used as `wc_Sha384`). #[repr(C)] pub struct wc_Sha512([u8; 512]); /// Stub for wolfCrypt `wc_Sha256` struct. #[repr(C)] pub struct wc_Sha256([u8; 256]); /// Stub for wolfCrypt `wc_Sha3` struct. #[repr(C)] pub struct wc_Sha3([u8; 512]); /// Stub for wolfCrypt `Blake2b` struct. #[repr(C)] pub struct Blake2b([u8; 512]); /// Stub for wolfCrypt `curve25519_key` struct. #[repr(C)] pub struct curve25519_key([u8; 256]); /// Stub for wolfCrypt `curve448_key` struct. #[repr(C)] pub struct curve448_key([u8; 256]); // ── AES-GCM ───────────────────────────────────────────────────────── pub unsafe fn wc_AesGcmSetKey(aes: *mut Aes, key: *const c_uchar, len: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_AesGcmEncrypt( aes: *mut Aes, out: *mut c_uchar, in_: *const c_uchar, sz: c_uint, iv: *const c_uchar, iv_sz: c_uint, auth_tag: *mut c_uchar, auth_tag_sz: c_uint, auth_in: *const c_uchar, auth_in_sz: c_uint, ) -> c_int { unreachable!() } pub unsafe fn wc_AesGcmDecrypt( aes: *mut Aes, out: *mut c_uchar, in_: *const c_uchar, sz: c_uint, iv: *const c_uchar, iv_sz: c_uint, auth_tag: *const c_uchar, auth_tag_sz: c_uint, auth_in: *const c_uchar, auth_in_sz: c_uint, ) -> c_int { unreachable!() } pub unsafe fn wc_AesInit(aes: *mut Aes, heap: *mut c_void, dev_id: c_int) -> c_int { unreachable!() } pub unsafe fn wc_AesFree(aes: *mut Aes) { unreachable!() } // ── ChaCha20-Poly1305 ──────────────────────────────────────────────── pub unsafe fn wc_ChaCha20Poly1305_Encrypt( key: *const c_uchar, iv: *const c_uchar, aad: *const c_uchar, aad_sz: c_uint, in_: *const c_uchar, in_sz: c_uint, out: *mut c_uchar, auth_tag: *mut c_uchar, ) -> c_int { unreachable!() } pub unsafe fn wc_ChaCha20Poly1305_Decrypt( key: *const c_uchar, iv: *const c_uchar, aad: *const c_uchar, aad_sz: c_uint, in_: *const c_uchar, in_sz: c_uint, auth_tag: *const c_uchar, out: *mut c_uchar, ) -> c_int { unreachable!() } pub unsafe fn wc_XChaCha20Poly1305_Encrypt( dst: *mut c_uchar, dst_space: usize, src: *const c_uchar, src_len: usize, ad: *const c_uchar, ad_len: usize, nonce: *const c_uchar, nonce_len: usize, key: *const c_uchar, key_len: usize, ) -> c_int { unreachable!() } pub unsafe fn wc_XChaCha20Poly1305_Decrypt( dst: *mut c_uchar, dst_space: usize, src: *const c_uchar, src_len: usize, ad: *const c_uchar, ad_len: usize, nonce: *const c_uchar, nonce_len: usize, key: *const c_uchar, key_len: usize, ) -> c_int { unreachable!() } // ── SHA-256 (init/update/final) ────────────────────────────────────── pub unsafe fn wc_InitSha256(sha: *mut wc_Sha256) -> c_int { unreachable!() } pub unsafe fn wc_Sha256Update(sha: *mut wc_Sha256, data: *const c_uchar, len: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_Sha256Final(sha: *mut wc_Sha256, hash: *mut c_uchar) -> c_int { unreachable!() } pub unsafe fn wc_Sha256Free(sha: *mut wc_Sha256) { unreachable!() } // ── SHA-384 (init/update/final) ────────────────────────────────────── // wc_Sha384 is typedef wc_Sha512 in wolfSSL; bindgen exposes wc_Sha512. pub unsafe fn wc_InitSha384(sha: *mut wc_Sha512) -> c_int { unreachable!() } pub unsafe fn wc_Sha384Update(sha: *mut wc_Sha512, data: *const c_uchar, len: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_Sha384Final(sha: *mut wc_Sha512, hash: *mut c_uchar) -> c_int { unreachable!() } pub unsafe fn wc_Sha384Free(sha: *mut wc_Sha512) { unreachable!() } // ── SHA-512 (init/update/final) ────────────────────────────────────── pub unsafe fn wc_InitSha512(sha: *mut wc_Sha512) -> c_int { unreachable!() } pub unsafe fn wc_Sha512Update(sha: *mut wc_Sha512, data: *const c_uchar, len: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_Sha512Final(sha: *mut wc_Sha512, hash: *mut c_uchar) -> c_int { unreachable!() } pub unsafe fn wc_Sha512Free(sha: *mut wc_Sha512) { unreachable!() } // ── SHA3-256 (init/update/final) ───────────────────────────────────── pub unsafe fn wc_InitSha3_256(sha: *mut wc_Sha3, heap: *mut c_void, dev_id: c_int) -> c_int { unreachable!() } pub unsafe fn wc_Sha3_256_Update(sha: *mut wc_Sha3, data: *const c_uchar, len: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_Sha3_256_Final(sha: *mut wc_Sha3, hash: *mut c_uchar) -> c_int { unreachable!() } pub unsafe fn wc_Sha3_256_Free(sha: *mut wc_Sha3) { unreachable!() } // ── SHA3-512 (init/update/final) ───────────────────────────────────── pub unsafe fn wc_InitSha3_512(sha: *mut wc_Sha3, heap: *mut c_void, dev_id: c_int) -> c_int { unreachable!() } pub unsafe fn wc_Sha3_512_Update(sha: *mut wc_Sha3, data: *const c_uchar, len: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_Sha3_512_Final(sha: *mut wc_Sha3, hash: *mut c_uchar) -> c_int { unreachable!() } pub unsafe fn wc_Sha3_512_Free(sha: *mut wc_Sha3) { unreachable!() } // ── BLAKE2b (init/update/final) ────────────────────────────────────── pub unsafe fn wc_InitBlake2b(b2b: *mut Blake2b, digest_sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_InitBlake2b_WithKey( b2b: *mut Blake2b, digest_sz: c_uint, key: *const c_uchar, key_sz: c_uint, ) -> c_int { unreachable!() } pub unsafe fn wc_Blake2bUpdate(b2b: *mut Blake2b, in_: *const c_uchar, in_sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_Blake2bFinal(b2b: *mut Blake2b, final_: *mut c_uchar, request_sz: c_uint) -> c_int { unreachable!() } // ── HMAC ──────────────────────────────────────────────────────────── pub unsafe fn wc_HmacInit(hmac: *mut Hmac, heap: *mut c_void, dev_id: c_int) -> c_int { unreachable!() } pub unsafe fn wc_HmacSetKey(hmac: *mut Hmac, type_: c_int, key: *const c_uchar, key_sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_HmacUpdate(hmac: *mut Hmac, in_: *const c_uchar, in_sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_HmacFinal(hmac: *mut Hmac, out: *mut c_uchar) -> c_int { unreachable!() } pub unsafe fn wc_HmacFree(hmac: *mut Hmac) { unreachable!() } // ── HKDF (TLS-1.3 Extract — RFC 5869 Extract step) ────────────────── pub unsafe fn wc_Tls13_HKDF_Extract( prk: *mut c_uchar, salt: *const c_uchar, salt_len: c_uint, ikm: *mut c_uchar, ikm_len: c_uint, digest: c_int, ) -> c_int { unreachable!() } // ── RNG ───────────────────────────────────────────────────────────── pub unsafe fn wc_InitRng(rng: *mut WC_RNG) -> c_int { unreachable!() } pub unsafe fn wc_RNG_GenerateBlock(rng: *mut WC_RNG, buf: *mut c_uchar, sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_FreeRng(rng: *mut WC_RNG) -> c_int { unreachable!() } // ── Curve25519 ─────────────────────────────────────────────────────── pub unsafe fn wc_curve25519_make_key(rng: *mut WC_RNG, key_sz: c_int, key: *mut curve25519_key) -> c_int { unreachable!() } pub unsafe fn wc_curve25519_init(key: *mut curve25519_key) -> c_int { unreachable!() } pub unsafe fn wc_curve25519_export_key_raw( key: *mut curve25519_key, priv_: *mut c_uchar, priv_sz: *mut c_uint, pub_: *mut c_uchar, pub_sz: *mut c_uint, ) -> c_int { unreachable!() } pub unsafe fn wc_curve25519_import_private( priv_: *const c_uchar, priv_sz: c_uint, key: *mut curve25519_key, ) -> c_int { unreachable!() } pub unsafe fn wc_curve25519_import_public( pub_: *const c_uchar, pub_sz: c_uint, key: *mut curve25519_key, ) -> c_int { unreachable!() } pub unsafe fn wc_curve25519_shared_secret_ex( local: *mut curve25519_key, remote: *mut curve25519_key, out: *mut c_uchar, out_sz: *mut c_uint, endian: c_int, ) -> c_int { unreachable!() } pub unsafe fn wc_curve25519_free(key: *mut curve25519_key) { unreachable!() } // ── Curve448 ───────────────────────────────────────────────────────── pub unsafe fn wc_curve448_make_key(rng: *mut WC_RNG, key_sz: c_int, key: *mut curve448_key) -> c_int { unreachable!() } pub unsafe fn wc_curve448_init(key: *mut curve448_key) -> c_int { unreachable!() } pub unsafe fn wc_curve448_export_key_raw( key: *mut curve448_key, priv_: *mut c_uchar, priv_sz: *mut c_uint, pub_: *mut c_uchar, pub_sz: *mut c_uint, ) -> c_int { unreachable!() } pub unsafe fn wc_curve448_import_private( priv_: *const c_uchar, priv_sz: c_uint, key: *mut curve448_key, ) -> c_int { unreachable!() } pub unsafe fn wc_curve448_import_public( pub_: *const c_uchar, pub_sz: c_uint, key: *mut curve448_key, ) -> c_int { unreachable!() } pub unsafe fn wc_curve448_shared_secret_ex( local: *mut curve448_key, remote: *mut curve448_key, out: *mut c_uchar, out_sz: *mut c_uint, endian: c_int, ) -> c_int { unreachable!() } pub unsafe fn wc_curve448_free(key: *mut curve448_key) { unreachable!() } } } pub use provider::WolfSslProvider; /// Register the wolfSSL provider into the global /// [`ProviderRegistry`][ccc_crypto_core::registry::ProviderRegistry]. /// /// Call this once from `ccc_init()` in the bridge crate. pub fn init() { let provider = WolfSslProvider::new(); ccc_crypto_core::ProviderRegistry::global() .register("wolfssl", Box::new(provider)); log::info!("[ccc-crypto-wolfssl] provider registered"); }