Skip to content

Commit b1072da

Browse files
authored
Merge pull request #22 from gasbytes/rust-improvements
Rust improvements
2 parents 55e5e78 + 9cfb191 commit b1072da

File tree

8 files changed

+480
-292
lines changed

8 files changed

+480
-292
lines changed
Lines changed: 130 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,79 @@
1-
/// Custom error type for cryptographic operations, only indicating failure.
2-
/// Errors are generalized to avoid the leaking of information.
1+
use core::fmt;
2+
3+
/// Custom error type for cryptographic operations.
4+
/// Groups common wolfCrypt error types into categories.
35
#[derive(Debug)]
46
pub enum WCError {
7+
/// Operation completed successfully (ret = 0)
8+
Success,
9+
/// Generic failure (-1)
510
Failure,
11+
/// Memory-related errors (MEMORY_E, MP_MEM, etc.)
12+
Memory,
13+
/// Invalid arguments or state (BAD_FUNC_ARG, BAD_STATE_E, etc.)
14+
InvalidArgument,
15+
/// Buffer-related errors (BUFFER_E, RSA_BUFFER_E, etc.)
16+
Buffer,
17+
/// Authentication failures (MAC_CMP_FAILED_E, AES_GCM_AUTH_E, etc.)
18+
Authentication,
19+
/// Random number generation errors (RNG_FAILURE_E, MISSING_RNG_E, etc.)
20+
RandomError,
21+
/// ASN parsing errors (ASN_PARSE_E and related)
22+
ASNParse,
23+
/// Key-related errors (RSA_KEY_PAIR_E, ECC_PRIV_KEY_E, etc.)
24+
KeyError,
25+
/// Feature not available (NOT_COMPILED_IN, CRYPTOCB_UNAVAILABLE, etc.)
26+
NotAvailable,
27+
}
28+
29+
impl fmt::Display for WCError {
30+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31+
match self {
32+
WCError::Success => write!(f, "Operation successful"),
33+
WCError::Failure => write!(f, "Operation failed"),
34+
WCError::Memory => write!(f, "Memory allocation error"),
35+
WCError::InvalidArgument => write!(f, "Invalid argument or state"),
36+
WCError::Buffer => write!(f, "Buffer error"),
37+
WCError::Authentication => write!(f, "Authentication failed"),
38+
WCError::RandomError => write!(f, "Random number generation error"),
39+
WCError::ASNParse => write!(f, "ASN parsing error"),
40+
WCError::KeyError => write!(f, "Key-related error"),
41+
WCError::NotAvailable => write!(f, "Feature not available"),
42+
}
43+
}
644
}
745

846
/// A result type for cryptographic operations.
947
pub type WCResult = Result<(), WCError>;
1048

49+
/// Internal function to map wolfCrypt error codes to WCError variants
50+
fn check_error(ret: i32) -> WCResult {
51+
match ret {
52+
0 => Ok(()),
53+
-1 => Err(WCError::Failure),
54+
-125 => Err(WCError::Memory),
55+
-173 => Err(WCError::InvalidArgument),
56+
-132 => Err(WCError::Buffer),
57+
-181..=-180 | -213 => Err(WCError::Authentication),
58+
-199 | -236 => Err(WCError::RandomError),
59+
-162..=-140 => Err(WCError::ASNParse),
60+
-262 | -216 => Err(WCError::KeyError),
61+
-174 | -271 => Err(WCError::NotAvailable),
62+
_ => Err(WCError::Failure),
63+
}
64+
}
65+
1166
/// Checks if the FFI return value is `0` (indicating success).
1267
/// Returns `Ok(())` if success, otherwise returns `Err(CryptoError::Failure)`
1368
/// if the value is not `0`.
1469
///
1570
/// # Arguments
16-
/// * `stat` - The return value from the FFI call (i32).
71+
/// * `ret` - The return value from the FFI call (i32).
1772
///
1873
/// # Returns
1974
/// `CryptoResult` indicating either success or failure.
2075
pub fn check_if_zero(ret: i32) -> WCResult {
21-
if ret == 0 {
22-
Ok(())
23-
} else {
24-
Err(WCError::Failure)
25-
}
76+
check_error(ret)
2677
}
2778

2879
/// Checks if the FFI return value is `1` (indicating success).
@@ -35,10 +86,10 @@ pub fn check_if_zero(ret: i32) -> WCResult {
3586
/// # Returns
3687
/// `CryptoResult` indicating either success or failure.
3788
pub fn check_if_one(stat: i32) -> WCResult {
38-
if stat == 1 {
39-
Ok(())
40-
} else {
41-
Err(WCError::Failure)
89+
match stat {
90+
1 => Ok(()),
91+
0 => Err(WCError::Failure),
92+
_ => check_error(stat),
4293
}
4394
}
4495

@@ -52,9 +103,72 @@ pub fn check_if_one(stat: i32) -> WCResult {
52103
/// # Returns
53104
/// `CryptoResult` indicating either success or failure.
54105
pub fn check_if_greater_than_zero(ret: i32) -> WCResult {
55-
if ret > 0 {
56-
Ok(())
57-
} else {
58-
Err(WCError::Failure)
106+
match ret {
107+
x if x > 0 => Ok(()),
108+
0 => Err(WCError::Failure),
109+
_ => check_error(ret),
110+
}
111+
}
112+
113+
#[cfg(test)]
114+
mod tests {
115+
use super::*;
116+
117+
#[test]
118+
fn test_error_display() {
119+
assert_eq!(WCError::Success.to_string(), "Operation successful");
120+
assert_eq!(WCError::Failure.to_string(), "Operation failed");
121+
assert_eq!(WCError::Memory.to_string(), "Memory allocation error");
122+
assert_eq!(
123+
WCError::InvalidArgument.to_string(),
124+
"Invalid argument or state"
125+
);
126+
assert_eq!(WCError::Buffer.to_string(), "Buffer error");
127+
assert_eq!(WCError::Authentication.to_string(), "Authentication failed");
128+
assert_eq!(
129+
WCError::RandomError.to_string(),
130+
"Random number generation error"
131+
);
132+
assert_eq!(WCError::ASNParse.to_string(), "ASN parsing error");
133+
assert_eq!(WCError::KeyError.to_string(), "Key-related error");
134+
assert_eq!(WCError::NotAvailable.to_string(), "Feature not available");
135+
}
136+
137+
#[test]
138+
fn test_check_error() {
139+
assert!(check_error(0).is_ok());
140+
assert!(matches!(check_error(-1), Err(WCError::Failure)));
141+
assert!(matches!(check_error(-125), Err(WCError::Memory)));
142+
assert!(matches!(check_error(-173), Err(WCError::InvalidArgument)));
143+
assert!(matches!(check_error(-132), Err(WCError::Buffer)));
144+
assert!(matches!(check_error(-180), Err(WCError::Authentication)));
145+
assert!(matches!(check_error(-199), Err(WCError::RandomError)));
146+
assert!(matches!(check_error(-140), Err(WCError::ASNParse)));
147+
assert!(matches!(check_error(-262), Err(WCError::KeyError)));
148+
assert!(matches!(check_error(-174), Err(WCError::NotAvailable)));
149+
}
150+
151+
#[test]
152+
fn test_check_if_zero() {
153+
assert!(check_if_zero(0).is_ok());
154+
assert!(matches!(check_if_zero(-1), Err(WCError::Failure)));
155+
assert!(matches!(check_if_zero(-125), Err(WCError::Memory)));
156+
}
157+
158+
#[test]
159+
fn test_check_if_one() {
160+
assert!(check_if_one(1).is_ok());
161+
assert!(check_if_one(0).is_err());
162+
assert!(matches!(check_if_one(-1), Err(WCError::Failure)));
163+
}
164+
165+
#[test]
166+
fn test_check_if_greater_than_zero() {
167+
assert!(check_if_greater_than_zero(1).is_ok());
168+
assert!(check_if_greater_than_zero(0).is_err());
169+
assert!(matches!(
170+
check_if_greater_than_zero(-1),
171+
Err(WCError::Failure)
172+
));
59173
}
60174
}

rustls-wolfcrypt-provider/src/kx/sec256r1.rs

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
use crate::{error::check_if_zero, types::*};
22
use alloc::boxed::Box;
3-
use alloc::vec;
4-
use alloc::vec::Vec;
53
use core::mem;
64
use core::ptr;
75
use foreign_types::ForeignType;
86
use wolfcrypt_rs::*;
97

108
pub struct KeyExchangeSecP256r1 {
11-
priv_key_bytes: Vec<u8>,
12-
pub_key_bytes: Vec<u8>,
9+
priv_key_bytes: Box<[u8]>,
10+
pub_key_bytes: Box<[u8]>,
1311
}
1412

1513
pub struct ECCPubKey {
16-
qx: Vec<u8>,
14+
qx: [u8; 32],
1715
qx_len: word32,
18-
qy: Vec<u8>,
16+
qy: [u8; 32],
1917
qy_len: word32,
2018
}
2119

@@ -27,21 +25,18 @@ impl KeyExchangeSecP256r1 {
2725
let rng_object: WCRngObject = WCRngObject::new(&mut rng);
2826
let mut ret;
2927
let mut pub_key_raw = ECCPubKey {
30-
qx: [0; 32].to_vec(),
28+
qx: [0; 32],
3129
qx_len: 32,
32-
qy: [0; 32].to_vec(),
30+
qy: [0; 32],
3331
qy_len: 32,
3432
};
3533

36-
// We initiliaze the ecc key object.
3734
key_object.init();
38-
39-
// We initiliaze the rng object.
4035
rng_object.init();
4136

4237
let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_id_ECC_SECP256R1) };
4338

44-
let mut priv_key_raw: Vec<u8> = vec![0; key_size as usize];
39+
let mut priv_key_raw = [0u8; 32];
4540
let mut priv_key_raw_len: word32 = priv_key_raw.len() as word32;
4641

4742
ret = unsafe {
@@ -73,33 +68,31 @@ impl KeyExchangeSecP256r1 {
7368
)
7469
};
7570
check_if_zero(ret).unwrap();
71+
// One byte prefix (0x04) + 32 bytes X coord + 32 bytes Y coord
72+
let mut pub_key_bytes = [0x04; 65];
7673

77-
let mut pub_key_bytes = Vec::new();
74+
// Copy X coordinate into bytes 1-32
75+
pub_key_bytes[1..33].copy_from_slice(&pub_key_raw.qx);
7876

79-
pub_key_bytes.push(0x04);
80-
pub_key_bytes.extend(pub_key_raw.qx.clone());
81-
pub_key_bytes.extend(pub_key_raw.qy.clone());
82-
pub_key_bytes.as_slice();
77+
// Copy Y coordinate into bytes 33-64
78+
pub_key_bytes[33..65].copy_from_slice(&pub_key_raw.qy);
8379

8480
KeyExchangeSecP256r1 {
85-
priv_key_bytes: priv_key_raw.to_vec(),
86-
pub_key_bytes: pub_key_bytes.to_vec(),
81+
priv_key_bytes: Box::new(priv_key_raw),
82+
pub_key_bytes: Box::new(pub_key_bytes),
8783
}
8884
}
8985

90-
pub fn derive_shared_secret(&self, peer_pub_key: Vec<u8>) -> Vec<u8> {
86+
pub fn derive_shared_secret(&self, peer_pub_key: &[u8]) -> Box<[u8]> {
9187
let mut priv_key: ecc_key = unsafe { mem::zeroed() };
9288
let priv_key_object = ECCKeyObject::new(&mut priv_key);
9389
let mut pub_key: ecc_key = unsafe { mem::zeroed() };
9490
let pub_key_object = ECCKeyObject::new(&mut pub_key);
95-
let mut ret;
9691
let mut rng: WC_RNG = unsafe { mem::zeroed() };
9792
let rng_object = WCRngObject::new(&mut rng);
93+
let mut ret: i32;
9894

99-
// We initialize the private key before we import it.
10095
priv_key_object.init();
101-
102-
// We initiliaze the public key before we import it.
10396
pub_key_object.init();
10497

10598
ret = unsafe {
@@ -114,10 +107,6 @@ impl KeyExchangeSecP256r1 {
114107
};
115108
check_if_zero(ret).unwrap();
116109

117-
/*
118-
* Skipping first byte because rustls uses this format:
119-
* https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2.
120-
* */
121110
ret = unsafe {
122111
wc_ecc_import_unsigned(
123112
pub_key_object.as_ptr(),
@@ -129,7 +118,6 @@ impl KeyExchangeSecP256r1 {
129118
};
130119
check_if_zero(ret).unwrap();
131120

132-
// We initialize the rng object.
133121
rng_object.init();
134122

135123
ret = unsafe { wc_ecc_set_rng(pub_key_object.as_ptr(), rng_object.as_ptr()) };
@@ -138,9 +126,7 @@ impl KeyExchangeSecP256r1 {
138126
ret = unsafe { wc_ecc_set_rng(priv_key_object.as_ptr(), rng_object.as_ptr()) };
139127
check_if_zero(ret).unwrap();
140128

141-
let key_size = unsafe { wc_ecc_get_curve_size_from_id(ecc_curve_id_ECC_SECP256R1) };
142-
143-
let mut out: Vec<u8> = vec![0; key_size as usize];
129+
let mut out = [0u8; 32];
144130
let mut out_len: word32 = out.len() as word32;
145131

146132
ret = unsafe {
@@ -153,7 +139,7 @@ impl KeyExchangeSecP256r1 {
153139
};
154140
check_if_zero(ret).unwrap();
155141

156-
out.to_vec()
142+
Box::new(out)
157143
}
158144
}
159145

@@ -162,15 +148,12 @@ impl rustls::crypto::ActiveKeyExchange for KeyExchangeSecP256r1 {
162148
self: Box<Self>,
163149
peer_pub_key: &[u8],
164150
) -> Result<rustls::crypto::SharedSecret, rustls::Error> {
165-
// We derive the shared secret with our private key and
166-
// the received public key.
167-
let secret = self.derive_shared_secret(peer_pub_key.to_vec());
168-
169-
Ok(rustls::crypto::SharedSecret::from(secret.as_slice()))
151+
let secret = self.derive_shared_secret(peer_pub_key);
152+
Ok(rustls::crypto::SharedSecret::from(&*secret))
170153
}
171154

172155
fn pub_key(&self) -> &[u8] {
173-
self.pub_key_bytes.as_slice()
156+
&self.pub_key_bytes
174157
}
175158

176159
fn group(&self) -> rustls::NamedGroup {
@@ -189,8 +172,8 @@ mod tests {
189172
let bob = Box::new(KeyExchangeSecP256r1::use_secp256r1());
190173

191174
assert_eq!(
192-
alice.derive_shared_secret(bob.pub_key().try_into().unwrap()),
193-
bob.derive_shared_secret(alice.pub_key().try_into().unwrap()),
175+
alice.derive_shared_secret(bob.pub_key()),
176+
bob.derive_shared_secret(alice.pub_key()),
194177
)
195178
}
196179
}

0 commit comments

Comments
 (0)