signed_note/lib.rs
1// Ported from "mod" (https://pkg.go.dev/golang.org/x/mod)
2// Copyright 2009 The Go Authors
3// Licensed under the BSD-3-Clause license found in the LICENSE file or at https://opensource.org/licenses/BSD-3-Clause
4//
5// This ports code from the original Go project "mod" and adapts it to Rust idioms.
6//
7// Modifications and Rust implementation Copyright (c) 2025 Cloudflare, Inc.
8// Licensed under the BSD-3-Clause license found in the LICENSE file or at https://opensource.org/licenses/BSD-3-Clause
9
10//! This crate defines notes as specified by the [C2SP signed-note](https://c2sp.org/signed-note) specification.
11//!
12//! This file contains code ported from the original project [note](https://pkg.go.dev/golang.org/x/mod/sumdb/note).
13//!
14//! References:
15//! - [note](https://cs.opensource.google/go/x/mod/+/refs/tags/v0.21.0:sumdb/note/)
16//!
17//! # Signed Note
18//!
19//! A note is text signed by one or more server keys ([spec](https://c2sp.org/signed-note#note)).
20//! The text should be ignored unless the note is signed by a trusted server key and the signature
21//! has been verified using the server's public key.
22//!
23//! A server's public key is identified by a name, typically the "host[/path]" giving the base URL
24//! of the server's transparency log. The syntactic restrictions on a name are that it be
25//! non-empty, well-formed UTF-8 containing neither Unicode spaces nor plus (U+002B).
26//!
27//! A server signs texts using public key cryptography. A given server may have multiple public
28//! keys, each identified by a 32-bit ID of the public key. The [`key_id`] function computes the
29//! key ID as RECOMMENDED by the [spec](https://c2sp.org/signed-note#signatures).
30//! ```text
31//! key ID = SHA-256(key name || 0x0A || signature type || public key)[:4]
32//! ```
33//!
34//! A [`Note`] represents a text with one or more signatures. An implementation can reject a note
35//! with too many signatures (for example, more than 100 signatures).
36//!
37//! The [`Note::from_bytes`] function parses a message and validates that the text and signatures are
38//! syntactically valid, and returns a Note.
39//!
40//! The [`Note::new`] function accepts a text and an existing list of signatures and returns a Note.
41//!
42//! A [Signature] represents a signature on a note, verified or not
43//! ([spec](https://c2sp.org/signed-note.md#signatures)).
44//!
45//! The [`Signature::from_bytes`] function parses a note signature line and ensures that it is
46//! syntactically valid, returning a Signature.
47//!
48//! The [`Signature::to_bytes`] function encodes a signature for inclusion in a note.
49//!
50//! ## Verifying Notes
51//!
52//! A [`Verifier`] allows verification of signatures by one server public key. It can report the
53//! name of the server and the uint32 ID of the key, and it can verify a purported signature by
54//! that key.
55//!
56//! The standard implementation of a Verifier is constructed by [`StandardVerifier::new`] starting
57//! from a verifier key, which is a plain text string of the form `<name>+<id>+<keydata>`.
58//!
59//! A [`Verifiers`] allows looking up a Verifier by the combination of server name and key ID.
60//!
61//! The standard implementation of a Verifiers is constructed by [`VerifierList`] from a list of
62//! known verifiers.
63//!
64//! The [`Note::verify`] function attempts to verify the signatures on a note using the provided
65//! Verifiers, and returns the verified and unverified signatures.
66//!
67//! ## Signing Notes
68//!
69//! A [`Signer`] allows signing a text with a given key. It can report the name of the server and the
70//! ID of the key and can sign a raw text using that key.
71//!
72//! The standard implementation of a Signer is constructed by [`StandardSigner::new`] starting from
73//! an encoded signer key, which is a plain text string of the form
74//! `PRIVATE+KEY+<name>+<id>+<keydata>`. Anyone with an encoded signer key can sign messages using
75//! that key, so it must be kept secret. The encoding begins with the literal text `PRIVATE+KEY` to
76//! avoid confusion with the public server key. This format is not required by the C2SP spec.
77//!
78//! The [`Note::add_sigs`] function adds new signatures to the note from the provided list of
79//! Signers.
80//!
81//! ## Signed Note Format
82//!
83//! A signed note consists of a text ending in newline (U+000A), followed by a blank line (only a
84//! newline), followed by one or more signature lines of this form: em dash (U+2014), space
85//! (U+0020), server name, space, base64-encoded signature, newline
86//! ([spec](https://c2sp.org/signed-note#format)).
87//!
88//! Signed notes must be valid UTF-8 and must not contain any ASCII control characters (those below
89//! U+0020) other than newline.
90//!
91//! A signature is a base64 encoding of 4+n bytes.
92//!
93//! The first four bytes in the signature are the uint32 key ID stored in big-endian order.
94//!
95//! The remaining n bytes are the result of using the specified key to sign the note text
96//! (including the final newline but not the separating blank line).
97//!
98//! The [`Note::to_bytes`] function encodes a note into signed note format.
99//!
100//! ## Generating Keys
101//!
102//! There is only one key type, Ed25519 with algorithm identifier 1. New key types may be
103//! introduced in the future as needed, although doing so will require deploying the new algorithms
104//! to all clients before starting to depend on them for signatures.
105//!
106//! The [`generate_key`] function generates and returns a new signer and corresponding verifier.
107//!
108//! ## Example
109//!
110//! Here is a well-formed signed note:
111//! ```text
112//! If you think cryptography is the answer to your problem,
113//! then you don't know what your problem is
114//! — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=
115//! ```
116//!
117//! It can be constructed and displayed using:
118//!
119//! ```
120//! use signed_note::{Note, StandardSigner};
121//!
122//! let skey = "PRIVATE+KEY+PeterNeumann+c74f20a3+AYEKFALVFGyNhPJEMzD1QIDr+Y7hfZx09iUvxdXHKDFz";
123//! let text = "If you think cryptography is the answer to your problem,\n\
124//! then you don't know what your problem is.\n";
125//!
126//! let signer = StandardSigner::new(skey).unwrap();
127//! let mut n = Note::new(text.as_bytes(), &[]).unwrap();
128//! n.add_sigs(&[&signer]).unwrap();
129//!
130//! let want = "If you think cryptography is the answer to your problem,\n\
131//! then you don't know what your problem is.\n\
132//! \n\
133//! — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=\n";
134//!
135//! assert_eq!(&n.to_bytes(), want.as_bytes());
136//! ```
137//!
138//! The note's text is two lines, including the final newline, and the text is purportedly signed
139//! by a server named "`PeterNeumann`". (Although server names are canonically base URLs, the only
140//! syntactic requirement is that they not contain spaces or newlines).
141//!
142//! If [`Note::verify`] is given access to a [`Verifiers`] including the [`Verifier`] for this key, then
143//! it will succeed at verifying the encoded message and returning the parsed [`Note`]:
144//!
145//! ```
146//! use signed_note::{Note, StandardVerifier, VerifierList};
147//!
148//! let vkey = "PeterNeumann+c74f20a3+ARpc2QcUPDhMQegwxbzhKqiBfsVkmqq/LDE4izWy10TW";
149//! let msg = "If you think cryptography is the answer to your problem,\n\
150//! then you don't know what your problem is.\n\
151//! \n\
152//! — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=\n";
153//!
154//! let verifier = StandardVerifier::new(vkey).unwrap();
155//! let n = Note::from_bytes(msg.as_bytes()).unwrap();
156//! let (verified_sigs, _) = n.verify(&VerifierList::new(vec![Box::new(verifier.clone())])).unwrap();
157//!
158//! let got = format!("{} ({:08x}):\n{}", verified_sigs[0].name(), verified_sigs[0].id(), std::str::from_utf8(n.text()).unwrap());
159//! let want = "PeterNeumann (c74f20a3):\n\
160//! If you think cryptography is the answer to your problem,\n\
161//! then you don't know what your problem is.\n";
162//! assert_eq!(want, got);
163//! ```
164//!
165//! You can add your own signature to this message by re-signing the note, which will produce a
166//! doubly-signed message.
167//!
168//! ### Sign and add signatures
169//! ```
170//! use signed_note::{Note, StandardSigner, StandardVerifier, VerifierList};
171//!
172//! let vkey = "PeterNeumann+c74f20a3+ARpc2QcUPDhMQegwxbzhKqiBfsVkmqq/LDE4izWy10TW";
173//! let msg = "If you think cryptography is the answer to your problem,\n\
174//! then you don't know what your problem is.\n\
175//! \n\
176//! — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=\n";
177//! let text = "If you think cryptography is the answer to your problem,\n\
178//! then you don't know what your problem is.\n";
179//!
180//! let mut n = Note::from_bytes(msg.as_bytes()).unwrap();
181//!
182//! let verifier = StandardVerifier::new(vkey).unwrap();
183//! let (verified_sigs, unverified_sigs) = n.verify(&VerifierList::new(vec![Box::new(verifier.clone())])).unwrap();
184//! assert_eq!(verified_sigs.len(), 1);
185//! assert!(unverified_sigs.is_empty());
186//!
187//! struct ZeroRng;
188//!
189//! impl rand_core::RngCore for ZeroRng {
190//! fn next_u32(&mut self) -> u32 {
191//! 0
192//! }
193//!
194//! fn next_u64(&mut self) -> u64 {
195//! 0
196//! }
197//!
198//! fn fill_bytes(&mut self, dest: &mut [u8]) {
199//! for byte in dest.iter_mut() {
200//! *byte = 0;
201//! }
202//! }
203//!
204//! fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
205//! self.fill_bytes(dest);
206//! Ok(())
207//! }
208//! }
209//!
210//! impl rand_core::CryptoRng for ZeroRng {}
211//!
212//! let (skey, _) = signed_note::generate_key(&mut ZeroRng{}, "EnochRoot");
213//! let signer = StandardSigner::new(&skey).unwrap();
214//! n.add_sigs(&[&signer]).unwrap();
215//!
216//! let got = n.to_bytes();
217//!
218//! let want = "If you think cryptography is the answer to your problem,\n\
219//! then you don't know what your problem is.\n\
220//! \n\
221//! — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=\n\
222//! — EnochRoot rwz+eBzmZa0SO3NbfRGzPCpDckykFXSdeX+MNtCOXm2/5n2tiOHp+vAF1aGrQ5ovTG01oOTGwnWLox33WWd1RvMc+QQ=\n";
223//!
224//! assert_eq!(got, want.as_bytes());
225//! ```
226
227use base64::prelude::*;
228use ed25519_dalek::{
229 Signer as Ed25519Signer, SigningKey as Ed25519SigningKey, Verifier as Ed25519Verifier,
230 VerifyingKey as Ed25519VerifyingKey,
231};
232use rand_core::CryptoRngCore;
233use sha2::{Digest, Sha256};
234use std::collections::{BTreeSet, HashMap};
235use thiserror::Error;
236
237const MAX_NOTE_SIZE: usize = 1_000_000;
238const MAX_NOTE_SIGNATURES: usize = 100;
239
240/// A Verifier verifies messages signed with a specific key.
241pub trait Verifier {
242 /// Returns the server name associated with the key.
243 /// The name must be non-empty and not have any Unicode spaces or pluses.
244 fn name(&self) -> &str;
245
246 /// Returns the key ID.
247 fn key_id(&self) -> u32;
248
249 /// Reports whether sig is a valid signature of msg.
250 fn verify(&self, msg: &[u8], sig: &[u8]) -> bool;
251}
252
253/// A Signer signs messages using a specific key.
254pub trait Signer {
255 /// Returns the server name associated with the key.
256 /// The name must be non-empty and not have any Unicode spaces or pluses.
257 fn name(&self) -> &str;
258
259 /// Returns the key ID.
260 fn key_id(&self) -> u32;
261
262 /// Returns a signature for the given message.
263 ///
264 /// # Errors
265 ///
266 /// Returns a [`signature::Error`] if signing fails.
267 fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, signature::Error>;
268}
269
270/// Computes the key ID for the given server name and encoded public key
271/// as RECOMMENDED at <https://c2sp.org/signed-note#signatures>.
272///
273/// # Panics
274///
275/// Panics if slice conversion fails, which should never happen.
276pub fn key_id(name: &str, key: &[u8]) -> u32 {
277 let mut hasher = Sha256::new();
278 hasher.update(name.as_bytes());
279 hasher.update(b"\n");
280 hasher.update(key);
281 let result = hasher.finalize();
282
283 u32::from_be_bytes(result[0..4].try_into().unwrap())
284}
285
286/// An error returned from the [`StandardVerifier::new`] function when
287/// constructing a [`StandardVerifier`] from an encoded verifier key.
288#[derive(Error, Debug)]
289pub enum VerifierError {
290 #[error("malformed verifier key")]
291 Format,
292 #[error("unknown verifier algorithm")]
293 Alg,
294 #[error("invalid verifier ID")]
295 Id,
296}
297
298const ALG_ED25519: u8 = 1;
299
300// Reports whether name is valid according to <https://c2sp.org/signed-note#format>.
301// It must be non-empty and not have any Unicode spaces or pluses.
302pub fn is_key_name_valid(name: &str) -> bool {
303 !(name.is_empty() || name.chars().any(char::is_whitespace) || name.contains('+'))
304}
305
306/// [`StandardVerifier`] is a trivial Verifier implementation.
307#[derive(Clone)]
308pub struct StandardVerifier {
309 name: String,
310 id: u32,
311 verifying_key: Ed25519VerifyingKey,
312}
313
314impl Verifier for StandardVerifier {
315 fn name(&self) -> &str {
316 &self.name
317 }
318 fn key_id(&self) -> u32 {
319 self.id
320 }
321 fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
322 let sig_bytes: [u8; ed25519_dalek::SIGNATURE_LENGTH] = match sig.try_into() {
323 Ok(ok) => ok,
324 Err(_) => return false,
325 };
326 self.verifying_key
327 .verify(msg, &ed25519_dalek::Signature::from_bytes(&sig_bytes))
328 .is_ok()
329 }
330}
331
332impl StandardVerifier {
333 /// Construct a new [Verifier] from an encoded verifier key.
334 ///
335 /// # Errors
336 ///
337 /// Returns a [`VerifierError`] if `vkey` is malformed or otherwise invalid.
338 pub fn new(vkey: &str) -> Result<Self, VerifierError> {
339 let (name, vkey) = vkey.split_once('+').ok_or(VerifierError::Format)?;
340 let (id16, key64) = vkey.split_once('+').ok_or(VerifierError::Format)?;
341
342 let id = u32::from_str_radix(id16, 16).map_err(|_| VerifierError::Format)?;
343 let key = BASE64_STANDARD
344 .decode(key64)
345 .map_err(|_| VerifierError::Format)?;
346
347 if id16.len() != 8 || !is_key_name_valid(name) || key.is_empty() {
348 return Err(VerifierError::Format);
349 }
350
351 if id != key_id(name, &key) {
352 return Err(VerifierError::Id);
353 }
354
355 let alg = key[0];
356 let key = &key[1..];
357 match alg {
358 ALG_ED25519 => {
359 let key_bytes: &[u8; ed25519_dalek::PUBLIC_KEY_LENGTH] =
360 &key.try_into().map_err(|_| VerifierError::Format)?;
361 let verifying_key = ed25519_dalek::VerifyingKey::from_bytes(key_bytes)
362 .map_err(|_| VerifierError::Format)?;
363 Ok(Self {
364 name: name.to_owned(),
365 id,
366 verifying_key,
367 })
368 }
369 _ => Err(VerifierError::Alg),
370 }
371 }
372}
373
374/// An error returned from the [`StandardSigner::new`] function when
375/// constructing a [`StandardSigner`] from an encoded signer key.
376#[derive(Error, Debug)]
377pub enum SignerError {
378 #[error("malformed verifier key")]
379 Format,
380 #[error("unknown verifier algorithm")]
381 Alg,
382 #[error("invalid verifier ID")]
383 Id,
384}
385
386/// [`StandardSigner`] is a trivial Signer implementation.
387#[derive(Clone)]
388pub struct StandardSigner {
389 name: String,
390 id: u32,
391 signing_key: Ed25519SigningKey,
392}
393
394impl Signer for StandardSigner {
395 fn name(&self) -> &str {
396 &self.name
397 }
398 fn key_id(&self) -> u32 {
399 self.id
400 }
401 fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, signature::Error> {
402 let sig = self.signing_key.try_sign(msg)?;
403 Ok(sig.to_vec())
404 }
405}
406
407impl StandardSigner {
408 /// Construct a new [Signer] from an encoded signer key.
409 ///
410 /// # Errors
411 ///
412 /// Returns a [`SignerError`] if `skey` is malformed or otherwise invalid.
413 pub fn new(skey: &str) -> Result<Self, SignerError> {
414 let (priv1, skey) = skey.split_once('+').ok_or(SignerError::Format)?;
415 let (priv2, skey) = skey.split_once('+').ok_or(SignerError::Format)?;
416 let (name, skey) = skey.split_once('+').ok_or(SignerError::Format)?;
417 let (id16, key64) = skey.split_once('+').ok_or(SignerError::Format)?;
418
419 let id = u32::from_str_radix(id16, 16).map_err(|_| SignerError::Format)?;
420 let key = BASE64_STANDARD
421 .decode(key64)
422 .map_err(|_| SignerError::Format)?;
423
424 if priv1 != "PRIVATE"
425 || priv2 != "KEY"
426 || id16.len() != 8
427 || !is_key_name_valid(name)
428 || key.is_empty()
429 {
430 return Err(SignerError::Format);
431 }
432
433 // Note: id is the hash of the public key and we have the private key.
434 // Must verify id after deriving public key.
435
436 let signer: StandardSigner;
437 let pubkey: Vec<u8>;
438
439 let alg = key[0];
440 let key = &key[1..];
441 match alg {
442 ALG_ED25519 => {
443 let signing_key =
444 ed25519_dalek::SigningKey::try_from(key).map_err(|_| SignerError::Format)?;
445
446 pubkey = [
447 &[ALG_ED25519],
448 ed25519_dalek::VerifyingKey::from(&signing_key)
449 .to_bytes()
450 .as_slice(),
451 ]
452 .concat();
453
454 signer = Self {
455 name: name.to_owned(),
456 id,
457 signing_key,
458 };
459 }
460 _ => {
461 return Err(SignerError::Alg);
462 }
463 }
464
465 if id != key_id(name, &pubkey) {
466 return Err(SignerError::Id);
467 }
468
469 Ok(signer)
470 }
471}
472
473/// Generates a signer and verifier key pair for a named server.
474/// The signer key skey is private and must be kept secret.
475pub fn generate_key<R: CryptoRngCore + ?Sized>(csprng: &mut R, name: &str) -> (String, String) {
476 let signing_key = ed25519_dalek::SigningKey::generate(csprng);
477
478 let pubkey = [
479 &[ALG_ED25519],
480 signing_key.verifying_key().to_bytes().as_slice(),
481 ]
482 .concat();
483 let privkey = [&[ALG_ED25519], signing_key.to_bytes().as_slice()].concat();
484 let skey = format!(
485 "PRIVATE+KEY+{}+{:08x}+{}",
486 name,
487 key_id(name, &pubkey),
488 BASE64_STANDARD.encode(privkey)
489 );
490 let vkey = new_ed25519_verifier_key(name, &signing_key.verifying_key());
491
492 (skey, vkey)
493}
494
495/// Returns an encoded verifier key using the given name and Ed25519 public key.
496pub fn new_ed25519_verifier_key(name: &str, key: &ed25519_dalek::VerifyingKey) -> String {
497 let pubkey = [&[ALG_ED25519], key.to_bytes().as_slice()].concat();
498 format!(
499 "{}+{:08x}+{}",
500 name,
501 key_id(name, &pubkey),
502 BASE64_STANDARD.encode(&pubkey)
503 )
504}
505
506/// [`Verifiers`] is a collection of known verifier keys.
507pub trait Verifiers {
508 /// Returns the [`Verifier`] associated with the key identified by the name and
509 /// id.
510 ///
511 /// # Errors
512 ///
513 /// If the (name, id) pair is unknown, return a [`VerificationError::UnknownKey`].
514 fn verifier(&self, name: &str, id: u32) -> Result<&dyn Verifier, VerificationError>;
515}
516
517type VerifierMap = HashMap<(String, u32), Vec<Box<dyn Verifier>>>;
518
519/// [`VerifierList`] is a [Verifiers] implementation that uses the given list of verifiers.
520pub struct VerifierList {
521 map: VerifierMap,
522}
523
524/// An error returned from a Verifier when verifying a signature.
525#[derive(Error, Debug)]
526pub enum VerificationError {
527 #[error("unknown key {name}+{id:08x}")]
528 UnknownKey { name: String, id: u32 },
529 #[error("ambiguous key {name}+{id:08x}")]
530 AmbiguousKey { name: String, id: u32 },
531}
532
533impl Verifiers for VerifierList {
534 fn verifier(&self, name: &str, id: u32) -> Result<&dyn Verifier, VerificationError> {
535 match self.map.get(&(name.to_owned(), id)) {
536 Some(verifiers) => {
537 if verifiers.len() > 1 {
538 return Err(VerificationError::AmbiguousKey {
539 name: name.to_owned(),
540 id,
541 });
542 }
543 Ok(&*verifiers[0])
544 }
545 None => Err(VerificationError::UnknownKey {
546 name: name.to_owned(),
547 id,
548 }),
549 }
550 }
551}
552
553impl VerifierList {
554 /// Returns a [Verifiers] implementation that uses the given list of verifiers.
555 pub fn new(list: Vec<Box<dyn Verifier>>) -> Self {
556 let mut map: VerifierMap = HashMap::new();
557 for verifier in list {
558 map.entry((verifier.name().to_owned(), verifier.key_id()))
559 .or_default()
560 .push(verifier);
561 }
562 VerifierList { map }
563 }
564}
565
566/// A Note is a text and signatures.
567#[derive(Debug, PartialEq)]
568pub struct Note {
569 /// Text of note. Guaranteed to be well-formed.
570 text: Vec<u8>,
571 /// Signatures on note. Guaranteed to be well-formed.
572 sigs: Vec<Signature>,
573}
574
575/// A Signature is a single signature found in a note.
576#[derive(Debug, PartialEq, Clone)]
577pub struct Signature {
578 /// Name for the key that generated the signature.
579 name: String,
580 /// Key ID for the key that generated the signature.
581 id: u32,
582 /// The signature bytes.
583 sig: Vec<u8>,
584}
585
586impl Signature {
587 /// Returns a new signature from the given name and base64-encoded signature string.
588 ///
589 /// # Errors
590 ///
591 /// Returns [`NoteError::MalformedNote`] if the name is invalid according to [`is_key_name_valid`].
592 ///
593 pub fn new(name: String, id: u32, sig: Vec<u8>) -> Result<Self, NoteError> {
594 if !is_key_name_valid(&name) {
595 return Err(NoteError::MalformedNote);
596 }
597 Ok(Self { name, id, sig })
598 }
599
600 /// Parse a signature line into a [Signature].
601 ///
602 /// # Errors
603 ///
604 /// Returns a [`NoteError`] if the note is malformed.
605 ///
606 /// # Panics
607 ///
608 /// Panics if slice conversion fails, which should never happen.
609 pub fn from_bytes(line: &[u8]) -> Result<Self, NoteError> {
610 let line = std::str::from_utf8(line).map_err(|_| NoteError::MalformedNote)?;
611 let line = line.strip_prefix("— ").ok_or(NoteError::MalformedNote)?;
612 let (name, b64) = line.split_once(' ').ok_or(NoteError::MalformedNote)?;
613 let sig = BASE64_STANDARD
614 .decode(b64)
615 .map_err(|_| NoteError::MalformedNote)?;
616 if b64.is_empty() || sig.len() < 5 {
617 return Err(NoteError::MalformedNote);
618 }
619 let id = u32::from_be_bytes(sig[..4].try_into().unwrap());
620 let sig = &sig[4..];
621 Signature::new(name.to_owned(), id, sig.to_owned())
622 }
623
624 /// Return a signature's name.
625 pub fn name(&self) -> &str {
626 &self.name
627 }
628
629 /// Return a signature's key ID.
630 pub fn id(&self) -> u32 {
631 self.id
632 }
633
634 /// Return the signature bytes.
635 pub fn signature(&self) -> &[u8] {
636 &self.sig
637 }
638
639 /// Encode a signature for inclusion in a note.
640 pub fn to_bytes(&self) -> Vec<u8> {
641 let hbuf = self.id.to_be_bytes();
642 let base64 = BASE64_STANDARD.encode([&hbuf, self.sig.as_slice()].concat());
643 format!("— {} {}\n", self.name, base64).into()
644 }
645}
646
647/// An error returned for issues parsing, verifying, or adding signatures to notes.
648#[derive(Error, Debug)]
649pub enum NoteError {
650 #[error("malformed note")]
651 MalformedNote,
652 #[error("invalid signer")]
653 InvalidSigner,
654 #[error("invalid signature for key {name}+{id:08x}")]
655 InvalidSignature { name: String, id: u32 },
656 #[error("verifier name or id doesn't match signature")]
657 MismatchedVerifier,
658 #[error("note has no verifiable signatures")]
659 UnverifiedNote,
660 #[error(transparent)]
661 VerificationError(#[from] VerificationError),
662 #[error(transparent)]
663 SignatureError(#[from] signature::Error),
664}
665
666impl Note {
667 /// Returns a new note, ensuring that the text is well-formed, and
668 /// appending the provided signatures.
669 ///
670 /// # Errors
671 ///
672 /// Returns a [`NoteError::MalformedNote`] if the text is larger than
673 /// we're willing to parse, cannot be decoded as UTF-8, or contains
674 /// any non-newline ASCII control characters.
675 pub fn new(text: &[u8], existing_sigs: &[Signature]) -> Result<Self, NoteError> {
676 // Set some upper limit on what we're willing to process.
677 if text.len() > MAX_NOTE_SIZE {
678 return Err(NoteError::MalformedNote);
679 }
680 // Must have valid UTF-8 with no non-newline ASCII control characters.
681 let text_str = std::str::from_utf8(text).map_err(|_| NoteError::MalformedNote)?;
682 for ch in text_str.chars() {
683 // Validation checks
684 if ch < '\u{0020}' && ch != '\n' {
685 return Err(NoteError::MalformedNote);
686 }
687 }
688 if !text_str.ends_with('\n') {
689 return Err(NoteError::MalformedNote);
690 }
691
692 Ok(Self {
693 text: text.to_owned(),
694 sigs: existing_sigs.into(),
695 })
696 }
697
698 /// Parses the message msg into a note, returning a [`NoteError`] if any of the text or signatures are malformed.
699 ///
700 /// # Errors
701 ///
702 /// Returns a [`NoteError::MalformedNote`] if the message is larger than
703 /// we're willing to parse, cannot be decoded as UTF-8, contains
704 /// any non-newline ASCII control characters, or is otherwise invalid.
705 pub fn from_bytes(msg: &[u8]) -> Result<Self, NoteError> {
706 // Set some upper limit on what we're willing to process.
707 if msg.len() > MAX_NOTE_SIZE {
708 return Err(NoteError::MalformedNote);
709 }
710 // Must have valid UTF-8 (implied by &str type) with no non-newline ASCII control characters.
711 let msg_str = std::str::from_utf8(msg).map_err(|_| NoteError::MalformedNote)?;
712 for ch in msg_str.chars() {
713 // Validation checks
714 if ch < '\u{0020}' && ch != '\n' {
715 return Err(NoteError::MalformedNote);
716 }
717 }
718
719 // Must end with signature block preceded by blank line.
720 let (text, sigs) = msg_str
721 .rsplit_once("\n\n")
722 .ok_or(NoteError::MalformedNote)?;
723
724 // Add back the newline at the end of the text block.
725 let text = format!("{text}\n");
726
727 let sigs = sigs.strip_suffix("\n").ok_or(NoteError::MalformedNote)?;
728
729 let mut parsed_sigs: Vec<Signature> = Vec::new();
730 let mut num_sig = 0;
731
732 for line in sigs.split('\n') {
733 let sig = Signature::from_bytes(line.as_bytes())?;
734 num_sig += 1;
735 if num_sig > MAX_NOTE_SIGNATURES {
736 return Err(NoteError::MalformedNote);
737 }
738 parsed_sigs.push(sig);
739 }
740
741 Self::new(text.as_bytes(), &parsed_sigs)
742 }
743
744 /// Checks signatures on the note for those from known verifiers.
745 ///
746 /// For each signature in the message, [`Note::verify`] calls known.verifier to find a verifier.
747 /// If known.verifier returns a verifier and the verifier accepts the signature,
748 /// [`Note::verify`] includes the signature in the returned list of verified signatures.
749 /// If known.verifier returns a [`VerificationError::UnknownKey`],
750 /// [`Note::verify`] includes the signature in the returned list of unverified signatures.
751 ///
752 /// # Errors
753 ///
754 /// If known.verifier returns a verifier but the verifier rejects the signature,
755 /// [`Note::verify`] returns a [`NoteError::InvalidSignature`].
756 /// If known.verifier returns any other error, [`Note::verify`] returns that error.
757 ///
758 /// If no known verifier has signed an otherwise valid note,
759 /// [`Note::verify`] returns an [`NoteError::UnverifiedNote`].
760 pub fn verify(
761 &self,
762 known: &impl Verifiers,
763 ) -> Result<(Vec<Signature>, Vec<Signature>), NoteError> {
764 let mut verified_sigs = Vec::new();
765 let mut unverified_sigs = Vec::new();
766 let mut seen = BTreeSet::new();
767 let mut seen_unverified = BTreeSet::new();
768 for sig in &self.sigs {
769 match known.verifier(&sig.name, sig.id) {
770 Ok(verifier) => {
771 if verifier.name() != sig.name || verifier.key_id() != sig.id {
772 return Err(NoteError::MismatchedVerifier);
773 }
774 if seen.contains(&(&sig.name, sig.id)) {
775 continue;
776 }
777 seen.insert((&sig.name, sig.id));
778 if !verifier.verify(&self.text, &sig.sig) {
779 return Err(NoteError::InvalidSignature {
780 name: sig.name.clone(),
781 id: sig.id,
782 });
783 }
784 verified_sigs.push(sig.clone());
785 }
786 Err(VerificationError::UnknownKey { name: _, id: _ }) => {
787 // Drop repeated identical unverified signatures.
788 if seen_unverified.contains(&sig.to_bytes()) {
789 continue;
790 }
791 seen_unverified.insert(sig.to_bytes());
792 unverified_sigs.push(sig.clone());
793 }
794 Err(e) => return Err(e.into()),
795 }
796 }
797 if verified_sigs.is_empty() {
798 return Err(NoteError::UnverifiedNote);
799 }
800 Ok((verified_sigs, unverified_sigs))
801 }
802
803 /// Signs the note with the given signers. The new signatures from
804 /// signers are listed in the encoded message after the existing
805 /// signatures already present in n.sigs. If any signer uses the same key
806 /// as an existing signature, the existing signature is removed.
807 ///
808 /// # Errors
809 ///
810 /// Returns an error if any signers have invalid names.
811 /// Names must be non-empty and not have any Unicode spaces or pluses.
812 pub fn add_sigs(&mut self, signers: &[&dyn Signer]) -> Result<(), NoteError> {
813 // Prepare signatures and populate 'have' set.
814 let mut new_sigs = Vec::new();
815 let mut have = BTreeSet::new();
816 for s in signers {
817 let name = s.name();
818 let id = s.key_id();
819 have.insert((name, id));
820 if !is_key_name_valid(name) {
821 return Err(NoteError::InvalidSigner);
822 }
823 let sig = s.sign(&self.text)?;
824 new_sigs.push(Signature::new(name.to_owned(), id, sig)?);
825 }
826
827 // Remove existing signatures that have been replaced by new ones.
828 self.sigs.retain(|sig| !have.contains(&(&sig.name, sig.id)));
829
830 // Add new signatures at the end.
831 self.sigs.extend(new_sigs);
832
833 Ok(())
834 }
835
836 /// Returns a well-formed signed note.
837 pub fn to_bytes(&self) -> Vec<u8> {
838 let mut buf = self.text.clone();
839 buf.push(b'\n');
840 for sig in &self.sigs {
841 buf.extend(&sig.to_bytes());
842 }
843 buf
844 }
845
846 /// Returns the note's text.
847 pub fn text(&self) -> &[u8] {
848 &self.text
849 }
850}
851
852#[cfg(test)]
853mod tests {
854
855 use super::*;
856 use rand::rngs::OsRng;
857 static NAME: &str = "EnochRoot";
858
859 fn test_signer_and_verifier(name: &str, signer: &dyn Signer, verifier: &dyn Verifier) {
860 assert_eq!(&name, &signer.name());
861 assert_eq!(&name, &verifier.name());
862 assert_eq!(signer.key_id(), verifier.key_id());
863
864 let msg: &[u8] = b"hi";
865 let sig = signer.sign(msg).unwrap();
866 assert!(verifier.verify(msg, &sig));
867 }
868
869 #[test]
870 fn test_generate_key() {
871 let (skey, vkey) = generate_key(&mut OsRng, NAME);
872
873 let signer = StandardSigner::new(&skey).unwrap();
874 let verifier = StandardVerifier::new(&vkey).unwrap();
875
876 test_signer_and_verifier(NAME, &signer, &verifier);
877 }
878
879 #[test]
880 fn test_from_ed25519() {
881 let signing_key = ed25519_dalek::SigningKey::generate(&mut OsRng);
882
883 let pubkey = [
884 &[ALG_ED25519],
885 signing_key.verifying_key().to_bytes().as_slice(),
886 ]
887 .concat();
888 let id = key_id(NAME, &pubkey);
889
890 let vkey = new_ed25519_verifier_key(NAME, &signing_key.verifying_key());
891 let verifier = StandardVerifier::new(&vkey).unwrap();
892
893 let signer = StandardSigner {
894 name: NAME.to_owned(),
895 id,
896 signing_key,
897 };
898
899 test_signer_and_verifier(NAME, &signer, &verifier);
900 }
901
902 struct BadSigner {
903 s: Box<dyn Signer>,
904 }
905
906 impl Signer for BadSigner {
907 fn name(&self) -> &'static str {
908 "bad name"
909 }
910 fn key_id(&self) -> u32 {
911 self.s.key_id()
912 }
913 fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, signature::Error> {
914 self.s.sign(msg)
915 }
916 }
917
918 struct ErrSigner {
919 s: Box<dyn Signer>,
920 }
921
922 impl Signer for ErrSigner {
923 fn name(&self) -> &str {
924 self.s.name()
925 }
926 fn key_id(&self) -> u32 {
927 self.s.key_id()
928 }
929 fn sign(&self, _msg: &[u8]) -> Result<Vec<u8>, signature::Error> {
930 Err(signature::Error::new())
931 }
932 }
933
934 #[test]
935 fn test_sign() {
936 let skey = "PRIVATE+KEY+PeterNeumann+c74f20a3+AYEKFALVFGyNhPJEMzD1QIDr+Y7hfZx09iUvxdXHKDFz";
937 let text = b"If you think cryptography is the answer to your problem,\n\
938 then you don't know what your problem is.\n";
939
940 let signer = StandardSigner::new(skey).unwrap();
941
942 let mut n = Note::new(text, &[]).unwrap();
943 n.add_sigs(&[&signer]).unwrap();
944 let want = "If you think cryptography is the answer to your problem,\n\
945 then you don't know what your problem is.\n\
946 \n\
947 — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=\n";
948
949 assert_eq!(n.to_bytes(), want.as_bytes());
950
951 // Check that existing signature is replaced by new one.
952 let mut n = Note::new(
953 text,
954 &[Signature::new("PeterNeumann".into(), 0xc74f_20a3, vec![]).unwrap()],
955 )
956 .unwrap();
957 n.add_sigs(&[&signer]).unwrap();
958 assert_eq!(n.to_bytes(), want.as_bytes());
959
960 // Check various bad inputs.
961
962 // Attempt to create note without terminating newline.
963 let err = Note::new(b"abc", &[]).unwrap_err();
964 assert!(matches!(err, NoteError::MalformedNote));
965
966 // Attempt to create signature with bad name.
967 let err = Signature::new("a+b".into(), 0, vec![]).unwrap_err();
968 assert!(matches!(err, NoteError::MalformedNote));
969
970 // Attempt to sign with bad signer.
971 let err = Note::new(text, &[])
972 .unwrap()
973 .add_sigs(&[&BadSigner {
974 s: Box::new(signer.clone()),
975 }])
976 .unwrap_err();
977 assert!(matches!(err, NoteError::InvalidSigner));
978
979 let err = Note::new(text, &[])
980 .unwrap()
981 .add_sigs(&[&ErrSigner {
982 s: Box::new(signer.clone()),
983 }])
984 .unwrap_err();
985 assert!(matches!(err, NoteError::SignatureError(_)));
986 }
987
988 struct FixedVerifier {
989 v: Box<dyn Verifier>,
990 }
991
992 impl Verifiers for FixedVerifier {
993 fn verifier(&self, _name: &str, _id: u32) -> Result<&dyn Verifier, VerificationError> {
994 Ok(&*self.v)
995 }
996 }
997
998 #[test]
999 fn test_open() {
1000 let peter_key = "PeterNeumann+c74f20a3+ARpc2QcUPDhMQegwxbzhKqiBfsVkmqq/LDE4izWy10TW";
1001 let peter_verifier = StandardVerifier::new(peter_key).unwrap();
1002
1003 let enoch_key = "EnochRoot+af0cfe78+ATtqJ7zOtqQtYqOo0CpvDXNlMhV3HeJDpjrASKGLWdop";
1004 let enoch_verifier = StandardVerifier::new(enoch_key).unwrap();
1005
1006 let text = "If you think cryptography is the answer to your problem,\n\
1007 then you don't know what your problem is.\n";
1008 let peter_sig = "— PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=\n";
1009 let enoch_sig = "— EnochRoot rwz+eBzmZa0SO3NbfRGzPCpDckykFXSdeX+MNtCOXm2/5n2tiOHp+vAF1aGrQ5ovTG01oOTGwnWLox33WWd1RvMc+QQ=\n";
1010
1011 let peter = Signature::from_bytes(peter_sig.trim_end().as_bytes()).unwrap();
1012 let enoch = Signature::from_bytes(enoch_sig.trim_end().as_bytes()).unwrap();
1013
1014 // Check one signature verified, one not.
1015 let n = Note::from_bytes(format!("{text}\n{peter_sig}{enoch_sig}").as_bytes()).unwrap();
1016 let (verified_sigs, unverified_sigs) = n
1017 .verify(&VerifierList::new(vec![Box::new(peter_verifier.clone())]))
1018 .unwrap();
1019 assert_eq!(n.text(), text.as_bytes());
1020 assert_eq!(verified_sigs, vec![peter.clone()]);
1021 assert_eq!(unverified_sigs, vec![enoch.clone()]);
1022
1023 // Check both verified.
1024 let (verified_sigs, unverified_sigs) = n
1025 .verify(&VerifierList::new(vec![
1026 Box::new(peter_verifier.clone()),
1027 Box::new(enoch_verifier.clone()),
1028 ]))
1029 .unwrap();
1030 assert_eq!(verified_sigs, vec![peter.clone(), enoch.clone()]);
1031 assert!(unverified_sigs.is_empty());
1032
1033 // Check both unverified.
1034 let err = n.verify(&VerifierList::new(vec![])).unwrap_err();
1035 assert!(matches!(err, NoteError::UnverifiedNote));
1036
1037 // Check duplicated verifier.
1038 let err = Note::from_bytes(format!("{text}\n{enoch_sig}").as_bytes())
1039 .unwrap()
1040 .verify(&VerifierList::new(vec![
1041 Box::new(enoch_verifier.clone()),
1042 Box::new(peter_verifier.clone()),
1043 Box::new(enoch_verifier.clone()),
1044 ]))
1045 .unwrap_err();
1046 assert_eq!(err.to_string(), "ambiguous key EnochRoot+af0cfe78");
1047
1048 // Check unused duplicated verifier.
1049 let _ = Note::from_bytes(format!("{text}\n{peter_sig}").as_bytes())
1050 .unwrap()
1051 .verify(&VerifierList::new(vec![
1052 Box::new(enoch_verifier.clone()),
1053 Box::new(peter_verifier.clone()),
1054 Box::new(enoch_verifier.clone()),
1055 ]))
1056 .unwrap();
1057
1058 // Check too many signatures.
1059 let err = Note::from_bytes(format!("{}\n{}", text, peter_sig.repeat(101)).as_bytes())
1060 .unwrap_err();
1061 assert!(matches!(err, NoteError::MalformedNote));
1062
1063 // Invalid signature.
1064 let invalid_sig = format!("{}ABCD{}", &peter_sig[..60], &peter_sig[60..]);
1065 let err = Note::from_bytes(format!("{text}\n{invalid_sig}").as_bytes())
1066 .unwrap()
1067 .verify(&VerifierList::new(vec![Box::new(peter_verifier.clone())]))
1068 .unwrap_err();
1069 assert_eq!(
1070 err.to_string(),
1071 "invalid signature for key PeterNeumann+c74f20a3"
1072 );
1073
1074 // Duplicated verified and unverified signatures.
1075 let enoch_abcd = Signature::from_bytes("— EnochRoot rwz+eBzmZa0SO3NbfRGzPCpDckykFXSdeX+MNtCOXm2/5nABCD2tiOHp+vAF1aGrQ5ovTG01oOTGwnWLox33WWd1RvMc+QQ="
1076 .as_bytes(),
1077 )
1078 .unwrap();
1079 let sigs = format!(
1080 "{peter_sig}{peter_sig}{peter_sig}{enoch_sig}{}ABCD{}",
1081 &enoch_sig[..60],
1082 &enoch_sig[60..]
1083 );
1084 let n = Note::from_bytes(format!("{text}\n{sigs}").as_bytes()).unwrap();
1085 let (verified_sigs, unverified_sigs) = n
1086 .verify(&VerifierList::new(vec![Box::new(peter_verifier.clone())]))
1087 .unwrap();
1088 assert_eq!(verified_sigs, vec![peter.clone()]);
1089 assert_eq!(unverified_sigs, vec![enoch.clone(), enoch_abcd.clone()]);
1090
1091 // Invalid encoded message syntax.
1092 let bad_msgs: Vec<Vec<u8>> = vec![
1093 text.as_bytes().to_vec(),
1094 format!("\n{text}").as_bytes().to_vec(),
1095 format!("{text}\n{}", &peter_sig[..peter_sig.len() - 1]).as_bytes().to_vec(),
1096 format!("\x01{text}\n{peter_sig}").as_bytes().to_vec(),
1097 [&[0xff], format!("{text}\n{peter_sig}").as_bytes()].concat(),
1098 format!("{text}\n— Bad Name x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=").as_bytes().to_vec(),
1099 ];
1100
1101 for msg in bad_msgs {
1102 let err = Note::from_bytes(&msg).unwrap_err();
1103 assert!(matches!(err, NoteError::MalformedNote));
1104 }
1105
1106 // Verifiers returns a Verifier for the wrong name or ID.
1107 let misnamed_sig = peter_sig.replace("PeterNeumann", "CarmenSandiego");
1108 let err = Note::from_bytes(format!("{text}\n{misnamed_sig}").as_bytes())
1109 .unwrap()
1110 .verify(&FixedVerifier {
1111 v: Box::new(peter_verifier.clone()),
1112 })
1113 .unwrap_err();
1114 assert!(matches!(err, NoteError::MismatchedVerifier));
1115
1116 let wrong_id = peter_sig.replace("x08g", "xxxx");
1117 let err = Note::from_bytes(format!("{text}\n{wrong_id}").as_bytes())
1118 .unwrap()
1119 .verify(&FixedVerifier {
1120 v: Box::new(peter_verifier.clone()),
1121 })
1122 .unwrap_err();
1123 assert!(matches!(err, NoteError::MismatchedVerifier));
1124 }
1125}