Skip to content

Commit 1fcbbbd

Browse files
fix(attest): use strict Ed25519 verification with regression test
Co-Authored-By: cairn-code <282421612+cairn-code@users.noreply.github.com>
1 parent 871b861 commit 1fcbbbd

1 file changed

Lines changed: 37 additions & 2 deletions

File tree

‎crates/gitlawb-attest/src/attestation.rs‎

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
//! by exact match.
1717
1818
use base64::{engine::general_purpose::URL_SAFE_NO_PAD as B64U, Engine};
19-
use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
19+
use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
2020
use serde::{de::DeserializeOwned, Deserialize, Serialize};
2121

2222
use crate::error::{Error, Result};
@@ -111,7 +111,7 @@ impl Attestation {
111111
.try_into()
112112
.map_err(|_| Error::Signature("signature must be 64 bytes".to_string()))?;
113113
let sig = Signature::from_bytes(&sig_bytes);
114-
vk.verify(&bytes, &sig)
114+
vk.verify_strict(&bytes, &sig)
115115
.map_err(|e| Error::Signature(format!("ed25519: {e}")))?;
116116

117117
Ok(vk)
@@ -554,4 +554,39 @@ mod tests {
554554
let err = tampered.verify_signature(cert_hash).unwrap_err();
555555
assert!(matches!(err, Error::Signature(_)));
556556
}
557+
558+
/// Regression guard for strict verification: a signature forged under a
559+
/// weak (small-order) public key satisfies the verification equation
560+
/// but must be rejected. The identity point is such a key: with R the
561+
/// identity and S = 0, [S]B - [k]A is the identity for any message.
562+
#[test]
563+
fn verify_rejects_weak_key_signature() {
564+
let mut weak_key_bytes = [0u8; 32];
565+
weak_key_bytes[0] = 1; // compressed identity point (y = 1, x = 0)
566+
let weak_vk = VerifyingKey::from_bytes(&weak_key_bytes).unwrap();
567+
assert!(weak_vk.is_weak(), "identity point must be a weak key");
568+
569+
let cert_hash = sample_cert_hash();
570+
let mut forged = [0u8; 64];
571+
forged[0] = 1; // R = identity point, S = 0
572+
let forged_sig = B64U.encode(forged);
573+
574+
// Build an attestation with the weak key as signer and the forged
575+
// signature. The weak-key check happens at verify time.
576+
let mut att = dummy_attestation(&SigningKey::generate(&mut OsRng), cert_hash);
577+
let mut buf = Vec::with_capacity(ED25519_MULTICODEC.len() + 32);
578+
buf.extend_from_slice(&ED25519_MULTICODEC);
579+
buf.extend_from_slice(&weak_key_bytes);
580+
att.signer = format!(
581+
"did:key:{}",
582+
multibase::encode(multibase::Base::Base58Btc, &buf)
583+
);
584+
att.sig = forged_sig;
585+
586+
let err = att.verify_signature(cert_hash).unwrap_err();
587+
assert!(
588+
matches!(err, Error::Signature(_)),
589+
"signature under a weak (small-order) public key must be rejected"
590+
);
591+
}
557592
}

0 commit comments

Comments
 (0)