huskies: merge 728_story_cryptographic_peer_handshake_with_trusted_keys_gating
This commit is contained in:
+28
-17
@@ -40,10 +40,7 @@
|
||||
//! verifier needs a set of allowed public keys; this module provides the
|
||||
//! `verify_challenge` primitive but leaves the allow-list to story 480.
|
||||
|
||||
use bft_json_crdt::keypair::{
|
||||
ED25519_PUBLIC_KEY_LENGTH, ED25519_SIGNATURE_LENGTH, Ed25519KeyPair, Ed25519PublicKey,
|
||||
Ed25519Signature, sign, verify,
|
||||
};
|
||||
use bft_json_crdt::keypair::{Ed25519KeyPair, Ed25519Signature, sign};
|
||||
use ed25519_dalek::SigningKey;
|
||||
use fastcrypto::traits::{KeyPair, ToFromBytes};
|
||||
use rand::RngCore;
|
||||
@@ -95,34 +92,48 @@ pub fn sign_challenge(keypair: &Ed25519KeyPair, challenge: &str) -> SignatureHex
|
||||
/// Verify that `signature_hex` is a valid Ed25519 signature over `challenge`
|
||||
/// produced by the private key corresponding to `pubkey_hex`.
|
||||
///
|
||||
/// Uses [`verify_message_strict`] internally — the strict (non-malleable)
|
||||
/// variant from `ed25519-dalek`. Cofactor-manipulated or otherwise
|
||||
/// non-canonical signatures are rejected.
|
||||
pub fn verify_challenge(pubkey_hex: &str, challenge: &str, signature_hex: &str) -> bool {
|
||||
verify_message_strict(pubkey_hex, challenge.as_bytes(), signature_hex)
|
||||
}
|
||||
|
||||
/// Verify an Ed25519 signature over an arbitrary `message` using
|
||||
/// `ed25519_dalek::VerifyingKey::verify_strict`.
|
||||
///
|
||||
/// Returns `true` only if:
|
||||
/// - `pubkey_hex` decodes to a valid 32-byte Ed25519 public key.
|
||||
/// - `signature_hex` decodes to a valid 64-byte Ed25519 signature.
|
||||
/// - The signature is cryptographically valid for `challenge`.
|
||||
/// - The signature is a strict (non-malleable) Ed25519 signature over `message`.
|
||||
///
|
||||
/// Returns `false` on any decode error or crypto failure — callers should
|
||||
/// treat `false` as an auth rejection and close the connection.
|
||||
pub fn verify_challenge(pubkey_hex: &str, challenge: &str, signature_hex: &str) -> bool {
|
||||
/// Returns `false` on any decode error or crypto failure.
|
||||
pub fn verify_message_strict(pubkey_hex: &str, message: &[u8], signature_hex: &str) -> bool {
|
||||
let pubkey_bytes = match hex_decode(pubkey_hex) {
|
||||
Some(b) if b.len() == ED25519_PUBLIC_KEY_LENGTH => b,
|
||||
Some(b) if b.len() == 32 => b,
|
||||
_ => return false,
|
||||
};
|
||||
let sig_bytes = match hex_decode(signature_hex) {
|
||||
Some(b) if b.len() == ED25519_SIGNATURE_LENGTH => b,
|
||||
Some(b) if b.len() == 64 => b,
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let pubkey = match Ed25519PublicKey::from_bytes(&pubkey_bytes) {
|
||||
let pubkey_arr: [u8; 32] = match pubkey_bytes.try_into() {
|
||||
Ok(a) => a,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let sig_arr: [u8; 64] = match sig_bytes.try_into() {
|
||||
Ok(a) => a,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
let verifying_key = match ed25519_dalek::VerifyingKey::from_bytes(&pubkey_arr) {
|
||||
Ok(k) => k,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let sig = ed25519_dalek::Signature::from_bytes(&sig_arr);
|
||||
|
||||
let sig = match Ed25519Signature::from_bytes(&sig_bytes) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
verify(pubkey, challenge.as_bytes(), sig)
|
||||
verifying_key.verify_strict(message, &sig).is_ok()
|
||||
}
|
||||
|
||||
// ── Public key helpers ────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user