lum_ccc_rust/crates/ccc-crypto-wolfssl/src/lib.rs

283 lines
15 KiB
Rust

//! # 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");
}