syndicate-rs/syndicate/src/sturdy.rs

144 lines
4.4 KiB
Rust
Raw Normal View History

2023-02-06 16:09:17 +00:00
use blake2::Blake2s256;
2021-07-15 07:13:31 +00:00
use getrandom::getrandom;
2023-02-06 16:09:17 +00:00
use hmac::{SimpleHmac, Mac};
2021-07-15 07:13:31 +00:00
use preserves::hex::HexParser;
use preserves::hex::HexFormatter;
use preserves::value::NestedValue;
use preserves::value::NoEmbeddedDomainCodec;
use preserves::value::packed::PackedWriter;
use preserves::value::packed::from_bytes;
use preserves_schema::Codec;
2021-07-15 07:13:31 +00:00
use std::io;
use super::language;
2021-07-15 07:13:31 +00:00
use super::error::Error;
use super::rewrite::CaveatError;
pub use super::schemas::sturdy::*;
#[derive(Debug)]
pub enum ValidationError {
2023-02-06 16:09:17 +00:00
SignatureError,
2021-07-15 07:13:31 +00:00
AttenuationError(CaveatError),
2023-02-08 23:17:12 +00:00
BadCaveatsField,
2021-07-15 07:13:31 +00:00
}
impl std::fmt::Display for ValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
2023-02-06 16:09:17 +00:00
ValidationError::SignatureError =>
2021-07-15 07:13:31 +00:00
write!(f, "Invalid SturdyRef signature"),
ValidationError::AttenuationError(e) =>
write!(f, "Invalid SturdyRef attenuation: {:?}", e),
2023-02-08 23:17:12 +00:00
ValidationError::BadCaveatsField =>
write!(f, "Invalid caveats field in SturdyRef parameters"),
2021-07-15 07:13:31 +00:00
}
}
}
impl std::error::Error for ValidationError {}
const KEY_LENGTH: usize = 16; // bytes; 128 bits
fn signature(key: &[u8], data: &[u8]) -> Vec<u8> {
2023-02-06 16:09:17 +00:00
let mut m = SimpleHmac::<Blake2s256>::new_from_slice(key).expect("valid key length");
2021-07-15 07:13:31 +00:00
m.update(data);
let mut result = m.finalize().into_bytes().to_vec();
result.truncate(KEY_LENGTH);
result
}
2023-02-06 13:48:18 +00:00
fn chain_signature(key: &[u8], chain: &[Caveat]) -> Vec<u8> {
let mut key = key.to_vec();
for c in chain {
key = signature(&key, &encode(&language().unparse(c)));
}
key
}
2021-07-15 07:13:31 +00:00
pub fn new_key() -> Vec<u8> {
let mut buf = vec![0; KEY_LENGTH];
getrandom(&mut buf).expect("successful random number generation");
buf
}
pub fn encode<N: NestedValue>(v: &N) -> Vec<u8> {
PackedWriter::encode(&mut NoEmbeddedDomainCodec, v).expect("no io errors")
2021-07-15 07:13:31 +00:00
}
pub fn decode<N: NestedValue>(bs: &[u8]) -> io::Result<N> {
2021-07-15 07:13:31 +00:00
from_bytes(bs, &mut NoEmbeddedDomainCodec)
}
impl SturdyRef {
pub fn mint(oid: _Any, key: &[u8]) -> Self {
let sig = signature(key, &encode(&oid));
2023-02-08 23:17:12 +00:00
SturdyRef::from_parts(oid, vec![], sig)
}
pub fn from_parts(oid: _Any, caveats: Vec<Caveat>, sig: Vec<u8>) -> Self {
SturdyRef {
parameters: Parameters {
oid,
sig,
caveats: if caveats.is_empty() {
CaveatsField::Absent
} else {
CaveatsField::Present { caveats }
}
}
}
2021-07-15 07:13:31 +00:00
}
pub fn from_hex(s: &str) -> Result<Self, Error> {
let binary = HexParser::Liberal.decode(s).expect("hex encoded sturdyref");
Ok(language().parse(&decode(&binary)?)?)
2021-07-15 07:13:31 +00:00
}
pub fn to_hex(&self) -> String {
HexFormatter::Packed.encode(&encode(&language().unparse(self)))
2021-07-15 07:13:31 +00:00
}
2023-02-08 23:17:12 +00:00
pub fn caveat_chain(&self) -> Result<&[Caveat], ValidationError> {
match &self.parameters.caveats {
CaveatsField::Absent => Ok(&[]),
CaveatsField::Invalid { .. } => Err(ValidationError::BadCaveatsField),
CaveatsField::Present { caveats } => Ok(caveats),
}
}
2021-07-15 07:13:31 +00:00
pub fn validate_and_attenuate(
&self,
key: &[u8],
unattenuated_target: &_Ptr,
) -> Result<_Ptr, ValidationError> {
2023-02-06 16:09:17 +00:00
self.validate(key).map_err(|_| ValidationError::SignatureError)?;
2021-07-15 07:13:31 +00:00
let target = unattenuated_target
2023-02-08 23:17:12 +00:00
.attenuate(self.caveat_chain()?)
2021-07-15 07:13:31 +00:00
.map_err(ValidationError::AttenuationError)?;
Ok(target)
}
2023-02-06 16:09:17 +00:00
pub fn validate(&self, key: &[u8]) -> Result<(), ()> {
2023-02-08 23:17:12 +00:00
let SturdyRef { parameters: Parameters { oid, sig, .. } } = self;
let key = chain_signature(&signature(&key, &encode(oid)),
self.caveat_chain().map_err(|_| ())?);
2021-07-15 07:13:31 +00:00
if &key == sig {
Ok(())
} else {
2023-02-06 16:09:17 +00:00
Err(())
2021-07-15 07:13:31 +00:00
}
}
2023-02-08 23:17:12 +00:00
pub fn attenuate(&self, attenuation: &[Caveat]) -> Result<Self, ValidationError> {
Caveat::validate_many(attenuation).map_err(ValidationError::AttenuationError)?;
let SturdyRef { parameters: Parameters { oid, sig, .. } } = self;
2021-07-15 07:13:31 +00:00
let oid = oid.clone();
2023-02-08 23:17:12 +00:00
let mut caveat_chain = self.caveat_chain()?.to_vec();
2023-02-06 13:48:18 +00:00
caveat_chain.extend(attenuation.iter().cloned());
let sig = chain_signature(&sig, attenuation);
2023-02-08 23:17:12 +00:00
Ok(SturdyRef::from_parts(oid, caveat_chain, sig))
2021-07-15 07:13:31 +00:00
}
}