Add ed25519 signing and public key derivation to native library
ober
b5a37982c91459980e157bbb36447bd0423e0e1d
--- a/jerboa-native-rs/Cargo.lock +++ b/jerboa-native-rs/Cargo.lock @@ -112,6 +112,12 @@ dependencies = [ ] [[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] name = "cpufeatures" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -148,6 +154,7 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", + "digest", "fiat-crypto", "rustc_version", "subtle", @@ -166,6 +173,16 @@ dependencies = [ ] [[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] name = "deranged" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -186,6 +203,30 @@ dependencies = [ ] [[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] name = "fallible-iterator" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -367,6 +408,7 @@ dependencies = [ name = "jerboa-native" version = "0.1.0" dependencies = [ + "ed25519-dalek", "flate2", "hkdf", "inotify", @@ -590,6 +632,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -934,6 +986,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] name = "simd-adler32" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -962,6 +1023,16 @@ dependencies = [ ] [[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] name = "stringprep" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/jerboa-native-rs/Cargo.toml +++ b/jerboa-native-rs/Cargo.toml @@ -15,6 +15,7 @@ libc = "0.2" rusqlite = { version = "0.32", features = ["bundled"] } postgres = "0.19" x25519-dalek = { version = "2", features = ["static_secrets"] } +ed25519-dalek = { version = "2", features = ["hazmat"] } hkdf = "0.12" sha2 = "0.10" rcgen = { version = "0.13", features = ["ring", "pem"] } new file mode 100644 --- /dev/null +++ b/jerboa-native-rs/src/ed25519.rs @@ -0,0 +1,62 @@ +use ed25519_dalek::{SigningKey, Signer}; + +/// Ed25519 sign — called from chez_ssh_shim.c when CHEZ_SSH_NO_OPENSSL is defined. +/// seed: 32-byte private key seed +/// data/datalen: message to sign +/// sig_out: 64-byte buffer for the signature +/// Returns 0 on success, -1 on error. +#[no_mangle] +pub extern "C" fn ed25519_sign_standalone( + seed: *const u8, + data: *const u8, + datalen: usize, + sig_out: *mut u8, +) -> i32 { + if seed.is_null() || sig_out.is_null() { + return -1; + } + if data.is_null() && datalen > 0 { + return -1; + } + let seed_bytes: [u8; 32] = unsafe { + let mut arr = [0u8; 32]; + std::ptr::copy_nonoverlapping(seed, arr.as_mut_ptr(), 32); + arr + }; + let signing_key = SigningKey::from_bytes(&seed_bytes); + let msg = if datalen == 0 { + &[] + } else { + unsafe { std::slice::from_raw_parts(data, datalen) } + }; + let signature = signing_key.sign(msg); + unsafe { + std::ptr::copy_nonoverlapping(signature.to_bytes().as_ptr(), sig_out, 64); + } + 0 +} + +/// Ed25519 derive public key from seed. +/// seed: 32-byte private key seed +/// pubkey_out: 32-byte buffer for the public key +/// Returns 0 on success, -1 on error. +#[no_mangle] +pub extern "C" fn ed25519_derive_pubkey_standalone( + seed: *const u8, + pubkey_out: *mut u8, +) -> i32 { + if seed.is_null() || pubkey_out.is_null() { + return -1; + } + let seed_bytes: [u8; 32] = unsafe { + let mut arr = [0u8; 32]; + std::ptr::copy_nonoverlapping(seed, arr.as_mut_ptr(), 32); + arr + }; + let signing_key = SigningKey::from_bytes(&seed_bytes); + let public_key = signing_key.verifying_key(); + unsafe { + std::ptr::copy_nonoverlapping(public_key.as_bytes().as_ptr(), pubkey_out, 32); + } + 0 +} --- a/jerboa-native-rs/src/lib.rs +++ b/jerboa-native-rs/src/lib.rs @@ -10,6 +10,7 @@ mod x509; mod antidebug; mod integrity; mod x25519; +mod ed25519; mod process_ctl; #[cfg(target_os = "linux")]