Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::fmt;
use ed25519_dalek::ed25519::signature::Verifier as _;
use sha2::{Digest, Sha256};

const HASH_SIZE: usize = 32;
const PUBKEY_SIZE: usize = 32;
const SIGNATURE_SIZE: usize = 64;
pub(crate) const HASH_SIZE: usize = 32;
pub(crate) const PUBKEY_SIZE: usize = 32;
pub(crate) const SIGNATURE_SIZE: usize = 64;

/// An Ed25519 public key.
#[derive(Clone, Eq, Hash, PartialEq)]
Expand Down
72 changes: 42 additions & 30 deletions src/io/ascii/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,28 @@ use crate::{
pub use parser::ParseAsciiError;
use parser::{Parser, Result};

const LOG_FIELD: &str = "log";
const SIZE_FIELD: &str = "size";
const LEAF_FIELD: &str = "leaf";
const MESSAGE_FIELD: &str = "message";
const VERSION_FIELD: &str = "version";
const ROOT_HASH_FIELD: &str = "root_hash";
const SIGNATURE_FIELD: &str = "signature";
const NODE_HASH_FIELD: &str = "node_hash";
const LEAF_INDEX_FIELD: &str = "leaf_index";
const PUBLIC_KEY_FIELD: &str = "public_key";
const COSIGNATURE_FIELD: &str = "cosignature";

impl SignedTreeHead {
pub fn from_ascii(input: &str) -> Result<Self> {
let mut p = Parser::new(input);
let size: u64 = p.parse("size")?;
let root_hash: Hash = p.parse("root_hash")?;
let signature: Signature = p.parse("signature")?;
let size: u64 = p.parse(SIZE_FIELD)?;
let root_hash: Hash = p.parse(ROOT_HASH_FIELD)?;
let signature: Signature = p.parse(SIGNATURE_FIELD)?;
let mut cosignatures = Vec::new();
while !p.at_end() {
let (keyhash, timestamp, cosignature): (Hash, u64, Signature) =
p.parse("cosignature")?;
p.parse(COSIGNATURE_FIELD)?;
cosignatures.push(WitnessCosignature {
keyhash,
timestamp,
Expand All @@ -36,13 +48,13 @@ impl SignedTreeHead {
#[allow(unused_must_use)]
pub fn to_ascii(&self) -> String {
let mut ascii = String::new();
writeln!(ascii, "size={}", self.size);
writeln!(ascii, "root_hash={:x}", self.root_hash);
writeln!(ascii, "signature={:x}", self.signature);
writeln!(ascii, "{SIZE_FIELD}={}", self.size);
writeln!(ascii, "{ROOT_HASH_FIELD}={:x}", self.root_hash);
writeln!(ascii, "{SIGNATURE_FIELD}={:x}", self.signature);
for cosig in self.cosignatures.iter() {
writeln!(
ascii,
"cosignature={:x} {} {:x}",
"{COSIGNATURE_FIELD}={:x} {} {:x}",
cosig.keyhash, cosig.timestamp, cosig.cosignature
);
}
Expand All @@ -53,10 +65,10 @@ impl SignedTreeHead {
impl InclusionProof {
pub fn from_ascii(input: &str) -> Result<Self> {
let mut p = Parser::new(input);
let leaf_index = p.parse("leaf_index")?;
let leaf_index = p.parse(LEAF_INDEX_FIELD)?;
let mut node_hashes = Vec::new();
while !p.at_end() {
let hash = p.parse("node_hash")?;
let hash = p.parse(NODE_HASH_FIELD)?;
node_hashes.push(hash);
}
Ok(Self {
Expand All @@ -68,9 +80,9 @@ impl InclusionProof {
#[allow(unused_must_use)]
pub fn to_ascii(&self) -> String {
let mut ascii = String::new();
writeln!(ascii, "leaf_index={}", self.leaf_index);
writeln!(ascii, "{LEAF_INDEX_FIELD}={}", self.leaf_index);
for h in self.node_hashes.iter() {
writeln!(ascii, "node_hash={h:x}");
writeln!(ascii, "{NODE_HASH_FIELD}={h:x}");
}
ascii
}
Expand All @@ -79,9 +91,9 @@ impl InclusionProof {
impl Protoleaf {
pub fn from_ascii(input: &str) -> Result<Self> {
let mut p = Parser::new(input);
let message = p.parse("message")?;
let signature = p.parse("signature")?;
let public_key = p.parse::<[u8; 32]>("public_key")?.into();
let message = p.parse(MESSAGE_FIELD)?;
let signature = p.parse(SIGNATURE_FIELD)?;
let public_key = p.parse(PUBLIC_KEY_FIELD)?;
Ok(Protoleaf {
message,
signature,
Expand All @@ -92,9 +104,9 @@ impl Protoleaf {
#[allow(unused_must_use)]
pub fn to_ascii(&self) -> String {
let mut ascii = String::new();
writeln!(ascii, "message={:x}", self.message);
writeln!(ascii, "signature={:x}", self.signature);
writeln!(ascii, "public_key={:x}", self.public_key);
writeln!(ascii, "{MESSAGE_FIELD}={:x}", self.message);
writeln!(ascii, "{SIGNATURE_FIELD}={:x}", self.signature);
writeln!(ascii, "{PUBLIC_KEY_FIELD}={:x}", self.public_key);
ascii
}
}
Expand All @@ -109,12 +121,12 @@ impl SigsumSignature {
)));
}
let mut p = Parser::new(parts[0]);
let version: u64 = p.parse("version")?;
let version: u64 = p.parse(VERSION_FIELD)?;
if version != 2 {
return Err(ParseAsciiError(format!("version {version} not supported")));
}
let log_keyhash = p.parse("log")?;
let (leaf_keyhash, leaf_signature) = p.parse("leaf")?;
let log_keyhash = p.parse(LOG_FIELD)?;
let (leaf_keyhash, leaf_signature) = p.parse(LEAF_FIELD)?;
if !p.at_end() {
return Err(ParseAsciiError(
"expected an empty line after 'leaf'".into(),
Expand All @@ -134,28 +146,28 @@ impl SigsumSignature {
#[allow(unused_must_use)]
pub fn to_ascii(&self) -> String {
let mut ascii = String::new();
writeln!(ascii, "version=2");
writeln!(ascii, "log={:x}", self.log_keyhash);
writeln!(ascii, "{VERSION_FIELD}=2");
writeln!(ascii, "{LOG_FIELD}={:x}", self.log_keyhash);
writeln!(
ascii,
"leaf={:x} {:x}",
"{LEAF_FIELD}={:x} {:x}",
self.leaf_keyhash, self.leaf_signature
);
writeln!(ascii);
writeln!(ascii, "size={}", self.sth.size);
writeln!(ascii, "root_hash={:x}", self.sth.root_hash);
writeln!(ascii, "signature={:x}", self.sth.signature);
writeln!(ascii, "{SIZE_FIELD}={}", self.sth.size);
writeln!(ascii, "{ROOT_HASH_FIELD}={:x}", self.sth.root_hash);
writeln!(ascii, "{SIGNATURE_FIELD}={:x}", self.sth.signature);
for cosig in self.sth.cosignatures.iter() {
writeln!(
ascii,
"cosignature={:x} {} {:x}",
"{COSIGNATURE_FIELD}={:x} {} {:x}",
cosig.keyhash, cosig.timestamp, cosig.cosignature
);
}
writeln!(ascii);
writeln!(ascii, "leaf_index={}", self.proof.leaf_index);
writeln!(ascii, "{LEAF_INDEX_FIELD}={}", self.proof.leaf_index);
for h in self.proof.node_hashes.iter() {
writeln!(ascii, "node_hash={h:x}");
writeln!(ascii, "{NODE_HASH_FIELD}={h:x}");
}
ascii
}
Expand Down
38 changes: 17 additions & 21 deletions src/io/ascii/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use std::fmt;
use std::iter::Peekable;
use std::str::Lines;

use crate::{Hash, Signature};
use crate::{
crypto::{HASH_SIZE, PUBKEY_SIZE, SIGNATURE_SIZE},
Hash, PublicKey, Signature,
};

#[derive(Debug)]
pub struct ParseAsciiError(pub(super) String);
Expand Down Expand Up @@ -68,39 +71,32 @@ impl AsciiValue for u64 {

impl AsciiValue for Hash {
fn from_ascii(s: &str) -> Result<Self> {
let input = s.as_bytes();
if input.len() != 64 {
bail!("invalid hex length");
}
let mut bytes = [0; 32];
for (i, b) in bytes.iter_mut().enumerate() {
*b = hexbyte(input, i)?;
}
let bytes = <[u8; HASH_SIZE]>::from_ascii(s)?;
Ok(Hash::from(bytes))
}
}

impl AsciiValue for Signature {
fn from_ascii(s: &str) -> Result<Self> {
let input = s.as_bytes();
if input.len() != 128 {
bail!("invalid hex length");
}
let mut bytes = [0; 64];
for (i, b) in bytes.iter_mut().enumerate() {
*b = hexbyte(input, i)?;
}
let bytes = <[u8; SIGNATURE_SIZE]>::from_ascii(s)?;
Ok(Self::from(bytes))
}
}

impl AsciiValue for [u8; 32] {
impl AsciiValue for PublicKey {
fn from_ascii(s: &str) -> Result<Self> {
let bytes = <[u8; PUBKEY_SIZE]>::from_ascii(s)?;
Ok(Self::from(bytes))
}
}

impl<const N: usize> AsciiValue for [u8; N] {
fn from_ascii(s: &str) -> Result<[u8; N]> {
let input = s.as_bytes();
if input.len() != 64 {
if input.len() != N * 2 {
bail!("invalid hex length");
}
let mut bytes = [0; 32];
let mut bytes = [0; N];
for (i, b) in bytes.iter_mut().enumerate() {
*b = hexbyte(input, i)?;
}
Expand All @@ -120,7 +116,7 @@ impl<V0: AsciiValue, V1: AsciiValue> AsciiValue for (V0, V1) {

impl<V0: AsciiValue, V1: AsciiValue, V2: AsciiValue> AsciiValue for (V0, V1, V2) {
fn from_ascii(s: &str) -> Result<Self> {
let splits: Vec<&str> = s.splitn(3, ' ').collect();
let splits: Vec<&str> = s.split(' ').collect();
if splits.len() != 3 {
bail!("expected 3 values, found {}", splits.len())
}
Expand Down
1 change: 0 additions & 1 deletion src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ fn verify_leaf(
for key in signers.iter() {
if Hash::new(key) == *keyhash {
let signed = [b"sigsum.org/v1/tree-leaf\x00".as_slice(), checksum.as_ref()].concat();
signed.len();
if key.verify_signature(&signed, signature) {
return Ok(());
} else {
Expand Down