diff --git a/ssign-core/src/sign.rs b/ssign-core/src/sign.rs index 028aee0..f7ee6a2 100644 --- a/ssign-core/src/sign.rs +++ b/ssign-core/src/sign.rs @@ -47,18 +47,57 @@ pub fn request(client: &Client, token: &str, card: &Card, sha256: &[u8; 32]) -> .context("signature task")? .1; + parse_signature_response(&resp, &digest_hex) +} + +fn parse_signature_response(resp: &[u8], digest_hex: &str) -> Result> { let arr: serde_json::Value = - serde_json::from_slice(&resp).context("signature result was not JSON")?; + serde_json::from_slice(resp).context("signature result was not JSON")?; // Result shape: [ { "": "" } ] let sig_hex = arr .as_array() .and_then(|a| a.first()) .and_then(|o| o.as_object()) - .and_then(|m| m.values().next()) + .and_then(|m| { + m.iter() + .find(|(digest, _)| digest.eq_ignore_ascii_case(digest_hex)) + .map(|(_, signature)| signature) + }) .and_then(|v| v.as_str()) .with_context(|| { - let snip: String = String::from_utf8_lossy(&resp).chars().take(300).collect(); - format!("no signature in the result; got: {snip}") + let snip: String = String::from_utf8_lossy(resp).chars().take(300).collect(); + format!("no signature for requested digest {digest_hex}; got: {snip}") })?; hex::decode(sig_hex).context("signature was not valid hex") } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn selects_the_signature_for_the_requested_digest() { + let response = br#"[{"other":"aa","wanted":"bb"}]"#; + assert_eq!( + parse_signature_response(response, "wanted").unwrap(), + vec![0xbb] + ); + } + + #[test] + fn selects_a_realistic_digest_regardless_of_hex_case() { + let digest = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + let response = + br#"[{"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF":"bb"}]"#; + assert_eq!( + parse_signature_response(response, digest).unwrap(), + vec![0xbb] + ); + } + + #[test] + fn rejects_a_response_without_the_requested_digest() { + let response = br#"[{"other":"aa"}]"#; + assert!(parse_signature_response(response, "wanted").is_err()); + } +}