Skip to main content

lib_q_core/wasm/
error.rs

1//! WASM Error Handling Module
2//!
3//! This module provides secure, consistent error handling for WASM bindings.
4//! It ensures all WASM functions return Result<T, JsValue> consistently and
5//! provides secure error conversion without information leakage.
6
7#[cfg(feature = "wasm")]
8use wasm_bindgen::prelude::*;
9
10use crate::error::Error;
11
12/// Convert Error to JsValue for WASM compatibility
13///
14/// This function provides secure error conversion that:
15/// - Prevents information leakage through error messages
16/// - Ensures consistent error handling across WASM bindings
17/// - Maintains security by not exposing internal implementation details
18#[cfg(feature = "wasm")]
19pub fn error_to_js_value(error: Error) -> JsValue {
20    // Security: Use generic error messages to prevent information leakage
21    let message = match error {
22        Error::InvalidAlgorithm { .. } => "Invalid algorithm specified",
23        Error::InvalidKeySize { .. } => "Invalid key size",
24        Error::InvalidMessageSize { .. } => "Invalid message size",
25        Error::InvalidNonceSize { .. } => "Invalid nonce size",
26        Error::InvalidSignatureSize { .. } => "Invalid signature",
27        Error::InvalidCiphertextSize { .. } => "Invalid ciphertext",
28        Error::InvalidPlaintextSize { .. } => "Invalid plaintext",
29        Error::InvalidKeyFormat => "Invalid key material",
30        Error::InvalidSecurityLevel { .. } => "Invalid security level",
31        Error::NotImplemented { .. } => "Feature not implemented",
32        Error::ProviderNotConfigured { .. } => "Provider not configured",
33        Error::VerificationFailed { .. } => "Verification failed",
34        Error::EncryptionFailed { .. } => "Encryption failed",
35        Error::DecryptionFailed { .. } => "Decryption failed",
36        Error::KeyGenerationFailed { .. } => "Key generation failed",
37        Error::RandomGenerationFailed { .. } => "Random generation failed",
38        Error::SigningFailed { .. } => "Signing failed",
39        Error::MemoryAllocationFailed { .. } => "Memory allocation failed",
40        Error::InternalError { .. } => "Internal error",
41        Error::UnsupportedOperation { .. } => "Unsupported operation",
42        Error::InvalidState { .. } => "Invalid context state",
43        Error::PluginDependencyError { .. } => "Plugin dependency error",
44        Error::PluginVersionIncompatible { .. } => "Plugin version incompatible",
45        Error::InvalidKey { .. } => "Invalid key",
46        Error::UnsupportedAlgorithm { .. } => "Unsupported algorithm",
47        Error::AuthenticationFailed { .. } => "Authentication failed",
48        Error::InvalidAssociatedDataSize { .. } => "Invalid associated data size",
49        Error::InvalidTagSize { .. } => "Invalid tag size",
50        Error::InvalidHashSize { .. } => "Invalid hash size",
51        Error::InvalidRandomnessSize { .. } => "Invalid randomness size",
52        Error::RandomBytesLengthInvalid { .. } => "Invalid random length",
53        Error::HexDecode(..) => "Invalid hex encoding",
54        Error::BufferTooSmall { .. } => "Insufficient buffer capacity",
55    };
56
57    JsValue::from_str(message)
58}
59
60/// Helper function to convert Result<T, Error> to Result<T, JsValue>
61///
62/// This function provides a secure conversion that:
63/// - Maintains type safety
64/// - Ensures consistent error handling
65/// - Prevents information leakage
66#[cfg(feature = "wasm")]
67pub fn convert_result<T>(result: Result<T, Error>) -> Result<T, JsValue> {
68    result.map_err(error_to_js_value)
69}
70
71/// WASM-safe algorithm parsing that returns JsValue errors
72///
73/// This function provides secure algorithm parsing that:
74/// - Validates input strings
75/// - Returns consistent error types
76/// - Prevents injection attacks
77#[cfg(feature = "wasm")]
78pub fn parse_algorithm_wasm(algorithm: &str) -> Result<crate::api::Algorithm, JsValue> {
79    // Security: Validate input length to prevent DoS attacks
80    if algorithm.len() > 64 {
81        return Err(JsValue::from_str("Algorithm name too long"));
82    }
83
84    // Reject control characters; allow Unicode for algorithm string forms that use non-ASCII.
85    // [`crate::wasm::conversions::WasmConversions::string_to_algorithm`].
86    if algorithm.chars().any(|c| c.is_control()) {
87        return Err(JsValue::from_str("Invalid algorithm name format"));
88    }
89
90    match crate::wasm::conversions::WasmConversions::string_to_algorithm(algorithm) {
91        Ok(a) => Ok(a),
92        Err(Error::UnsupportedAlgorithm { .. }) => Err(JsValue::from_str("Unsupported algorithm")),
93        Err(_) => Err(JsValue::from_str("Invalid algorithm specified")),
94    }
95}
96
97/// Secure WASM error handling macro
98///
99/// This macro provides secure error handling for WASM functions that:
100/// - Ensures consistent error types
101/// - Prevents information leakage
102/// - Maintains security boundaries
103#[cfg(feature = "wasm")]
104#[macro_export]
105macro_rules! wasm_result {
106    ($expr:expr) => {
107        match $expr {
108            Ok(value) => Ok(value),
109            Err(error) => Err($crate::wasm::error::error_to_js_value(error)),
110        }
111    };
112}
113
114/// Secure WASM validation macro
115///
116/// This macro provides secure validation for WASM inputs that:
117/// - Validates input parameters
118/// - Returns consistent error types
119/// - Prevents injection attacks
120#[cfg(feature = "wasm")]
121#[macro_export]
122macro_rules! wasm_validate {
123    ($condition:expr, $error_msg:expr) => {
124        if !$condition {
125            return Err(JsValue::from_str($error_msg));
126        }
127    };
128}
129
130/// Secure WASM serialization helper
131///
132/// This function provides secure serialization that:
133/// - Handles serialization errors gracefully
134/// - Returns consistent error types
135/// - Prevents information leakage
136#[cfg(feature = "wasm")]
137pub fn secure_serialize<T: serde::Serialize>(value: &T) -> Result<JsValue, JsValue> {
138    match serde_wasm_bindgen::to_value(value) {
139        Ok(js_value) => Ok(js_value),
140        Err(_) => Err(JsValue::from_str("Serialization error")),
141    }
142}
143
144/// Secure WASM deserialization helper
145///
146/// This function provides secure deserialization that:
147/// - Handles deserialization errors gracefully
148/// - Returns consistent error types
149/// - Prevents information leakage
150#[cfg(feature = "wasm")]
151pub fn secure_deserialize<T: serde::de::DeserializeOwned>(value: &JsValue) -> Result<T, JsValue> {
152    match serde_wasm_bindgen::from_value(value.clone()) {
153        Ok(deserialized) => Ok(deserialized),
154        Err(_) => Err(JsValue::from_str("Deserialization error")),
155    }
156}
157
158#[cfg(test)]
159mod tests {
160
161    #[test]
162    #[cfg(target_arch = "wasm32")]
163    fn test_error_conversion() {
164        let error = Error::InvalidAlgorithm { algorithm: "test" };
165        let js_error = error_to_js_value(error);
166        assert!(js_error.is_string());
167    }
168
169    #[test]
170    #[cfg(target_arch = "wasm32")]
171    fn test_algorithm_parsing() {
172        assert!(parse_algorithm_wasm("sha3-256").is_ok());
173        assert_eq!(
174            parse_algorithm_wasm("mldsa65").unwrap(),
175            crate::api::Algorithm::MlDsa65
176        );
177        assert_eq!(
178            parse_algorithm_wasm("ML-DSA-65").unwrap(),
179            crate::api::Algorithm::MlDsa65
180        );
181        assert_eq!(
182            parse_algorithm_wasm("slh-dsa-shake256-128f-robust").unwrap(),
183            crate::api::Algorithm::SlhDsaShake256128fRobust
184        );
185        assert_eq!(
186            parse_algorithm_wasm("SlhDsaShake256128fRobust").unwrap(),
187            crate::api::Algorithm::SlhDsaShake256128fRobust
188        );
189        assert!(parse_algorithm_wasm("invalid").is_err());
190        assert!(parse_algorithm_wasm(&"a".repeat(100)).is_err());
191    }
192
193    #[test]
194    #[cfg(target_arch = "wasm32")]
195    fn test_secure_serialization() {
196        let value = serde_json::json!({"test": "value"});
197        let result = secure_serialize(&value);
198        assert!(result.is_ok());
199    }
200}