#![cfg(wolfssl_rsa)]
use std::ptr;
use wolfcrypt_rs::{
wolfcrypt_rsa_export_private_pkcs1, wolfcrypt_rsa_export_public_spki, wolfcrypt_rsa_free,
wolfcrypt_rsa_generate, wolfcrypt_rsa_import_private_pkcs1, wolfcrypt_rsa_import_public_spki,
wolfcrypt_rsa_key_size_bytes, wolfcrypt_rsa_new,
};
unsafe fn export_private(ctx: *mut std::ffi::c_void) -> Vec<u8> {
unsafe {
let mut len = 0u32;
let rc = wolfcrypt_rsa_export_private_pkcs1(ctx, ptr::null_mut(), &mut len);
assert_eq!(rc, 0, "query private DER size failed: {rc}");
assert!(len > 0, "private DER size query returned 0");
let mut buf = vec![0u8; len as usize];
let mut actual = len;
let rc = wolfcrypt_rsa_export_private_pkcs1(ctx, buf.as_mut_ptr(), &mut actual);
assert_eq!(rc, 0, "export private DER failed: {rc}");
buf.truncate(actual as usize);
buf
}
}
unsafe fn export_public_spki(ctx: *mut std::ffi::c_void) -> Vec<u8> {
unsafe {
let mut len = 0u32;
let rc = wolfcrypt_rsa_export_public_spki(ctx, ptr::null_mut(), &mut len);
assert_eq!(rc, 0, "query public SPKI size failed: {rc}");
assert!(len > 0, "public SPKI size query returned 0");
let mut buf = vec![0u8; len as usize];
let mut actual = len;
let rc = wolfcrypt_rsa_export_public_spki(ctx, buf.as_mut_ptr(), &mut actual);
assert_eq!(rc, 0, "export public SPKI failed: {rc}");
buf.truncate(actual as usize);
buf
}
}
#[test]
fn rsa_key_size_bytes_2048() {
unsafe {
let ctx = wolfcrypt_rsa_new();
assert!(!ctx.is_null(), "wolfcrypt_rsa_new returned NULL");
let rc = wolfcrypt_rsa_generate(ctx, 2048);
assert_eq!(rc, 0, "wolfcrypt_rsa_generate(2048) failed: {rc}");
let sz = wolfcrypt_rsa_key_size_bytes(ctx as *const _);
assert_eq!(sz, 256, "expected 256 bytes for 2048-bit key; got {sz}");
wolfcrypt_rsa_free(ctx);
}
}
#[test]
fn rsa_private_key_roundtrip() {
unsafe {
let ctx = wolfcrypt_rsa_new();
assert!(!ctx.is_null(), "wolfcrypt_rsa_new returned NULL");
let rc = wolfcrypt_rsa_generate(ctx, 2048);
assert_eq!(rc, 0, "wolfcrypt_rsa_generate(2048) failed: {rc}");
let der1 = export_private(ctx);
assert!(
der1.len() > 100,
"private key DER suspiciously short: {} B",
der1.len()
);
assert_eq!(
der1[0], 0x30,
"private key DER must start with SEQUENCE tag (0x30)"
);
let ctx2 = wolfcrypt_rsa_new();
assert!(!ctx2.is_null());
let rc = wolfcrypt_rsa_import_private_pkcs1(ctx2, der1.as_ptr(), der1.len() as u32);
assert_eq!(rc, 0, "re-import private key failed: {rc}");
let der2 = export_private(ctx2);
assert_eq!(
der1, der2,
"private key DER round-trip produced different bytes"
);
wolfcrypt_rsa_free(ctx2);
wolfcrypt_rsa_free(ctx);
}
}
#[test]
fn rsa_public_key_spki_roundtrip() {
unsafe {
let ctx = wolfcrypt_rsa_new();
assert!(!ctx.is_null());
let rc = wolfcrypt_rsa_generate(ctx, 2048);
assert_eq!(rc, 0, "wolfcrypt_rsa_generate(2048) failed: {rc}");
let spki1 = export_public_spki(ctx);
assert!(
spki1.len() > 20,
"public SPKI suspiciously short: {} B",
spki1.len()
);
assert_eq!(
spki1[0], 0x30,
"public SPKI must start with SEQUENCE tag (0x30)"
);
let ctx2 = wolfcrypt_rsa_new();
assert!(!ctx2.is_null());
let rc = wolfcrypt_rsa_import_public_spki(ctx2, spki1.as_ptr(), spki1.len() as u32);
assert_eq!(rc, 0, "import public SPKI failed: {rc}");
let spki2 = export_public_spki(ctx2);
assert_eq!(
spki1, spki2,
"public SPKI round-trip produced different bytes"
);
wolfcrypt_rsa_free(ctx2);
wolfcrypt_rsa_free(ctx);
}
}
#[test]
fn rsa_import_garbage_private_fails() {
unsafe {
let ctx = wolfcrypt_rsa_new();
assert!(!ctx.is_null());
let garbage = [0xffu8; 128];
let rc = wolfcrypt_rsa_import_private_pkcs1(ctx, garbage.as_ptr(), garbage.len() as u32);
assert_ne!(rc, 0, "import of garbage DER must fail, but returned 0");
wolfcrypt_rsa_free(ctx);
}
}
#[test]
fn rsa_import_garbage_public_spki_fails() {
unsafe {
let ctx = wolfcrypt_rsa_new();
assert!(!ctx.is_null());
let garbage = [0x00u8; 64];
let rc = wolfcrypt_rsa_import_public_spki(ctx, garbage.as_ptr(), garbage.len() as u32);
assert_ne!(rc, 0, "import of garbage SPKI must fail, but returned 0");
wolfcrypt_rsa_free(ctx);
}
}
#[test]
fn rsa_free_null_is_safe() {
unsafe {
wolfcrypt_rsa_free(ptr::null_mut());
}
}
#[test]
fn rsa_generate_overwrites_key() {
unsafe {
let ctx = wolfcrypt_rsa_new();
assert!(!ctx.is_null());
let rc = wolfcrypt_rsa_generate(ctx, 2048);
assert_eq!(rc, 0, "first generate failed: {rc}");
let sz1 = wolfcrypt_rsa_key_size_bytes(ctx as *const _);
assert_eq!(sz1, 256);
let der1 = export_private(ctx);
wolfcrypt_rsa_free(ctx);
let ctx2 = wolfcrypt_rsa_new();
assert!(!ctx2.is_null());
let rc = wolfcrypt_rsa_generate(ctx2, 2048);
assert_eq!(rc, 0, "second generate failed: {rc}");
let der2 = export_private(ctx2);
assert_ne!(der1, der2, "two independently generated keys should differ");
wolfcrypt_rsa_free(ctx2);
}
}