Skip to content

Commit f8c86ce

Browse files
Rust wrapper: fix Ed25519/Ed448 signature verify failed return values
1 parent bbace5a commit f8c86ce

4 files changed

Lines changed: 267 additions & 0 deletions

File tree

wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,11 @@ impl Ed25519 {
946946
sys::wc_ed25519_verify_msg(signature.as_ptr(), signature_size,
947947
message.as_ptr(), message_size, &mut res, &mut self.ws_key)
948948
};
949+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
950+
// A well-formed but invalid signature is reported as Ok(false)
951+
// rather than an error.
952+
return Ok(false);
953+
}
949954
if rc != 0 {
950955
return Err(rc);
951956
}
@@ -998,6 +1003,11 @@ impl Ed25519 {
9981003
message.as_ptr(), message_size, &mut res, &mut self.ws_key,
9991004
context.as_ptr(), context_size)
10001005
};
1006+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1007+
// A well-formed but invalid signature is reported as Ok(false)
1008+
// rather than an error.
1009+
return Ok(false);
1010+
}
10011011
if rc != 0 {
10021012
return Err(rc);
10031013
}
@@ -1066,6 +1076,11 @@ impl Ed25519 {
10661076
hash.as_ptr(), hash_size, &mut res, &mut self.ws_key,
10671077
context_ptr, context_size)
10681078
};
1079+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1080+
// A well-formed but invalid signature is reported as Ok(false)
1081+
// rather than an error.
1082+
return Ok(false);
1083+
}
10691084
if rc != 0 {
10701085
return Err(rc);
10711086
}
@@ -1124,6 +1139,11 @@ impl Ed25519 {
11241139
message.as_ptr(), message_size, &mut res, &mut self.ws_key,
11251140
context_ptr, context_size)
11261141
};
1142+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1143+
// A well-formed but invalid signature is reported as Ok(false)
1144+
// rather than an error.
1145+
return Ok(false);
1146+
}
11271147
if rc != 0 {
11281148
return Err(rc);
11291149
}
@@ -1182,6 +1202,11 @@ impl Ed25519 {
11821202
din.as_ptr(), din_size, &mut res, &mut self.ws_key, typ,
11831203
context_ptr, context_size)
11841204
};
1205+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1206+
// A well-formed but invalid signature is reported as Ok(false)
1207+
// rather than an error.
1208+
return Ok(false);
1209+
}
11851210
if rc != 0 {
11861211
return Err(rc);
11871212
}
@@ -1323,6 +1348,11 @@ impl Ed25519 {
13231348
sys::wc_ed25519_verify_msg_final(signature.as_ptr(), signature_size,
13241349
&mut res, &mut self.ws_key)
13251350
};
1351+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1352+
// A well-formed but invalid signature is reported as Ok(false)
1353+
// rather than an error.
1354+
return Ok(false);
1355+
}
13261356
if rc != 0 {
13271357
return Err(rc);
13281358
}

wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,11 @@ impl Ed448 {
920920
message.as_ptr(), message_size, &mut res, &mut self.ws_key,
921921
context_ptr, context_size)
922922
};
923+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
924+
// A well-formed but invalid signature is reported as Ok(false)
925+
// rather than an error.
926+
return Ok(false);
927+
}
923928
if rc != 0 {
924929
return Err(rc);
925930
}
@@ -988,6 +993,11 @@ impl Ed448 {
988993
hash.as_ptr(), hash_size, &mut res, &mut self.ws_key,
989994
context_ptr, context_size)
990995
};
996+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
997+
// A well-formed but invalid signature is reported as Ok(false)
998+
// rather than an error.
999+
return Ok(false);
1000+
}
9911001
if rc != 0 {
9921002
return Err(rc);
9931003
}
@@ -1046,6 +1056,11 @@ impl Ed448 {
10461056
message.as_ptr(), message_size, &mut res, &mut self.ws_key,
10471057
context_ptr, context_size)
10481058
};
1059+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1060+
// A well-formed but invalid signature is reported as Ok(false)
1061+
// rather than an error.
1062+
return Ok(false);
1063+
}
10491064
if rc != 0 {
10501065
return Err(rc);
10511066
}
@@ -1104,6 +1119,11 @@ impl Ed448 {
11041119
din.as_ptr(), din_size, &mut res, &mut self.ws_key, typ,
11051120
context_ptr, context_size)
11061121
};
1122+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1123+
// A well-formed but invalid signature is reported as Ok(false)
1124+
// rather than an error.
1125+
return Ok(false);
1126+
}
11071127
if rc != 0 {
11081128
return Err(rc);
11091129
}
@@ -1248,6 +1268,11 @@ impl Ed448 {
12481268
sys::wc_ed448_verify_msg_final(signature.as_ptr(), signature_size,
12491269
&mut res, &mut self.ws_key)
12501270
};
1271+
if rc == sys::wolfCrypt_ErrorCodes_SIG_VERIFY_E {
1272+
// A well-formed but invalid signature is reported as Ok(false)
1273+
// rather than an error.
1274+
return Ok(false);
1275+
}
12511276
if rc != 0 {
12521277
return Err(rc);
12531278
}

wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,121 @@ fn test_ph_sign_verify() {
211211
assert!(signature_valid);
212212
}
213213

214+
// The following tests exercise the Ok(false) return path (a well-formed but
215+
// invalid signature) of every Ed25519 verify function. Each test signs a
216+
// message, then flips a bit in the R portion (first byte) of the signature.
217+
// This keeps the signature structurally valid (the S portion remains less
218+
// than the group order) but makes the verification comparison fail, which is
219+
// expected to produce Ok(false).
220+
//
221+
// The underlying wolfCrypt verify functions return SIG_VERIFY_E for a
222+
// well-formed but invalid signature instead of returning 0 with the result
223+
// flag cleared. The Rust wrappers map SIG_VERIFY_E to Ok(false) so that an
224+
// invalid signature is reported as Ok(false) rather than an error.
225+
226+
#[test]
227+
#[cfg(all(ed25519_sign, ed25519_verify))]
228+
fn test_verify_msg_bad_sig() {
229+
common::setup();
230+
231+
let mut rng = RNG::new().expect("Error creating RNG");
232+
let mut ed = Ed25519::generate(&mut rng).expect("Error with generate()");
233+
234+
let message = [0x42u8, 33, 55, 66];
235+
let mut signature = [0u8; Ed25519::SIG_SIZE];
236+
ed.sign_msg(&message, &mut signature).expect("Error with sign_msg()");
237+
signature[0] ^= 0x01;
238+
239+
assert_eq!(ed.verify_msg(&signature, &message), Ok(false));
240+
}
241+
242+
#[test]
243+
#[cfg(all(ed25519_sign, ed25519_verify))]
244+
fn test_verify_msg_ex_bad_sig() {
245+
common::setup();
246+
247+
let mut rng = RNG::new().expect("Error creating RNG");
248+
let mut ed = Ed25519::generate(&mut rng).expect("Error with generate()");
249+
250+
let message = [0x42u8, 33, 55, 66];
251+
let mut signature = [0u8; Ed25519::SIG_SIZE];
252+
ed.sign_msg_ex(&message, None, Ed25519::ED25519, &mut signature).expect("Error with sign_msg_ex()");
253+
signature[0] ^= 0x01;
254+
255+
assert_eq!(ed.verify_msg_ex(&signature, &message, None, Ed25519::ED25519), Ok(false));
256+
}
257+
258+
#[test]
259+
#[cfg(all(ed25519_sign, ed25519_verify))]
260+
fn test_verify_msg_ctx_bad_sig() {
261+
common::setup();
262+
263+
let mut rng = RNG::new().expect("Error creating RNG");
264+
let mut ed = Ed25519::generate(&mut rng).expect("Error with generate()");
265+
266+
let message = [0x42u8, 33, 55, 66];
267+
let context = b"context";
268+
let mut signature = [0u8; Ed25519::SIG_SIZE];
269+
ed.sign_msg_ctx(&message, context, &mut signature).expect("Error with sign_msg_ctx()");
270+
signature[0] ^= 0x01;
271+
272+
assert_eq!(ed.verify_msg_ctx(&signature, &message, context), Ok(false));
273+
}
274+
275+
#[test]
276+
#[cfg(all(ed25519_sign, ed25519_verify))]
277+
fn test_verify_msg_ph_bad_sig() {
278+
common::setup();
279+
280+
let mut rng = RNG::new().expect("Error creating RNG");
281+
let mut ed = Ed25519::generate(&mut rng).expect("Error with generate()");
282+
283+
let message = [0x42u8, 33, 55, 66];
284+
let context = b"context";
285+
let mut signature = [0u8; Ed25519::SIG_SIZE];
286+
ed.sign_msg_ph(&message, Some(context), &mut signature).expect("Error with sign_msg_ph()");
287+
signature[0] ^= 0x01;
288+
289+
assert_eq!(ed.verify_msg_ph(&signature, &message, Some(context)), Ok(false));
290+
}
291+
292+
#[test]
293+
#[cfg(all(ed25519_sign, ed25519_verify))]
294+
fn test_verify_hash_ph_bad_sig() {
295+
common::setup();
296+
297+
let mut rng = RNG::new().expect("Error creating RNG");
298+
let mut ed = Ed25519::generate(&mut rng).expect("Error with generate()");
299+
300+
let hash = [0x55u8; 64];
301+
let context = b"context";
302+
let mut signature = [0u8; Ed25519::SIG_SIZE];
303+
ed.sign_hash_ph(&hash, Some(context), &mut signature).expect("Error with sign_hash_ph()");
304+
signature[0] ^= 0x01;
305+
306+
assert_eq!(ed.verify_hash_ph(&signature, &hash, Some(context)), Ok(false));
307+
}
308+
309+
#[test]
310+
#[cfg(all(ed25519_sign, ed25519_streaming_verify))]
311+
fn test_verify_msg_final_bad_sig() {
312+
common::setup();
313+
314+
let mut rng = RNG::new().expect("Error creating RNG");
315+
let mut ed = Ed25519::generate(&mut rng).expect("Error with generate()");
316+
317+
let message = [0x42u8, 33, 55, 66];
318+
let mut signature = [0u8; Ed25519::SIG_SIZE];
319+
ed.sign_msg(&message, &mut signature).expect("Error with sign_msg()");
320+
signature[0] ^= 0x01;
321+
322+
ed.verify_msg_init(&signature, None, Ed25519::ED25519).expect("Error with verify_msg_init()");
323+
ed.verify_msg_update(&message[0..2]).expect("Error with verify_msg_update()");
324+
ed.verify_msg_update(&message[2..4]).expect("Error with verify_msg_update()");
325+
326+
assert_eq!(ed.verify_msg_final(&signature), Ok(false));
327+
}
328+
214329
#[test]
215330
#[cfg(all(ed25519_import, ed25519_export))]
216331
fn test_import_export() {

wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,103 @@ fn test_ph_sign_verify() {
215215
assert!(signature_valid);
216216
}
217217

218+
// The following tests exercise the Ok(false) return path (a well-formed but
219+
// invalid signature) of every Ed448 verify function. Each test signs a
220+
// message, then flips a bit in the R portion (first byte) of the signature.
221+
// This keeps the signature structurally valid (the S portion remains less
222+
// than the group order) but makes the verification comparison fail, which is
223+
// expected to produce Ok(false).
224+
//
225+
// The underlying wolfCrypt verify functions return SIG_VERIFY_E for a
226+
// well-formed but invalid signature instead of returning 0 with the result
227+
// flag cleared. The Rust wrappers map SIG_VERIFY_E to Ok(false) so that an
228+
// invalid signature is reported as Ok(false) rather than an error.
229+
230+
#[test]
231+
#[cfg(all(ed448_sign, ed448_verify))]
232+
fn test_verify_msg_bad_sig() {
233+
common::setup();
234+
235+
let mut rng = RNG::new().expect("Error creating RNG");
236+
let mut ed = Ed448::generate(&mut rng).expect("Error with generate()");
237+
238+
let message = [0x42u8, 33, 55, 66];
239+
let mut signature = [0u8; Ed448::SIG_SIZE];
240+
ed.sign_msg(&message, None, &mut signature).expect("Error with sign_msg()");
241+
signature[0] ^= 0x01;
242+
243+
assert_eq!(ed.verify_msg(&signature, &message, None), Ok(false));
244+
}
245+
246+
#[test]
247+
#[cfg(all(ed448_sign, ed448_verify))]
248+
fn test_verify_msg_ex_bad_sig() {
249+
common::setup();
250+
251+
let mut rng = RNG::new().expect("Error creating RNG");
252+
let mut ed = Ed448::generate(&mut rng).expect("Error with generate()");
253+
254+
let message = [0x42u8, 33, 55, 66];
255+
let mut signature = [0u8; Ed448::SIG_SIZE];
256+
ed.sign_msg_ex(&message, None, Ed448::ED448, &mut signature).expect("Error with sign_msg_ex()");
257+
signature[0] ^= 0x01;
258+
259+
assert_eq!(ed.verify_msg_ex(&signature, &message, None, Ed448::ED448), Ok(false));
260+
}
261+
262+
#[test]
263+
#[cfg(all(ed448_sign, ed448_verify))]
264+
fn test_verify_msg_ph_bad_sig() {
265+
common::setup();
266+
267+
let mut rng = RNG::new().expect("Error creating RNG");
268+
let mut ed = Ed448::generate(&mut rng).expect("Error with generate()");
269+
270+
let message = [0x42u8, 33, 55, 66];
271+
let context = b"context";
272+
let mut signature = [0u8; Ed448::SIG_SIZE];
273+
ed.sign_msg_ph(&message, Some(context), &mut signature).expect("Error with sign_msg_ph()");
274+
signature[0] ^= 0x01;
275+
276+
assert_eq!(ed.verify_msg_ph(&signature, &message, Some(context)), Ok(false));
277+
}
278+
279+
#[test]
280+
#[cfg(all(ed448_sign, ed448_verify))]
281+
fn test_verify_hash_ph_bad_sig() {
282+
common::setup();
283+
284+
let mut rng = RNG::new().expect("Error creating RNG");
285+
let mut ed = Ed448::generate(&mut rng).expect("Error with generate()");
286+
287+
let hash = [0x55u8; 64];
288+
let context = b"context";
289+
let mut signature = [0u8; Ed448::SIG_SIZE];
290+
ed.sign_hash_ph(&hash, Some(context), &mut signature).expect("Error with sign_hash_ph()");
291+
signature[0] ^= 0x01;
292+
293+
assert_eq!(ed.verify_hash_ph(&signature, &hash, Some(context)), Ok(false));
294+
}
295+
296+
#[test]
297+
#[cfg(all(ed448_sign, ed448_streaming_verify))]
298+
fn test_verify_msg_final_bad_sig() {
299+
common::setup();
300+
301+
let mut rng = RNG::new().expect("Error creating RNG");
302+
let mut ed = Ed448::generate(&mut rng).expect("Error with generate()");
303+
304+
let message = [0x42u8, 33, 55, 66];
305+
let mut signature = [0u8; Ed448::SIG_SIZE];
306+
ed.sign_msg(&message, None, &mut signature).expect("Error with sign_msg()");
307+
signature[0] ^= 0x01;
308+
309+
ed.verify_msg_init(&signature, None, Ed448::ED448).expect("Error with verify_msg_init()");
310+
ed.verify_msg_update(&message).expect("Error with verify_msg_update()");
311+
312+
assert_eq!(ed.verify_msg_final(&signature), Ok(false));
313+
}
314+
218315
#[test]
219316
#[cfg(all(ed448_import, ed448_export))]
220317
fn test_import_export() {

0 commit comments

Comments
 (0)