pub mod client;
#[cfg(all(feature = "fuzz", getrandom_backend = "custom"))]
pub mod random;
#[cfg(feature = "fuzz")]
pub mod seed;
pub mod server;
pub mod vector;
use crate::Attestation;
use darkbio_cobs as cobs;
use darkbio_crypto::cwt::claims::{self, eat};
use darkbio_crypto::{cwt, xdsa};
use std::cell::{Cell, RefCell};
use std::io::{self, Write};
use std::rc::Rc;
use vector::{Event, Vector};
pub const MAX_STEPS: usize = 64;
pub const TIMESTAMP: i64 = 0;
pub fn self_attestation(signer: &xdsa::SecretKey) -> Attestation {
let claims = darkbio_trust::device::HardwareClaims {
sub: claims::Subject { sub: "".into() },
cnf: claims::Confirm::new(signer.public_key()),
nbf: claims::NotBefore { nbf: 0 },
iat: claims::IssuedAt { iat: 0 },
oem: eat::Oemid::new_pen(0),
hwm: eat::HwModel { hw_model: vec![] },
hwv: eat::HwVersion::new("".into()),
};
let cwt = cwt::issue_at(
&claims,
signer,
darkbio_trust::CRYPTO_DOMAIN_DEVICE_ATTESTATION,
TIMESTAMP,
)
.unwrap();
Attestation::new(cwt).unwrap()
}
pub fn cloud_attestation(signer: &xdsa::SecretKey) -> Vec<u8> {
let claims = darkbio_trust::cloud::SignerClaims {
iss: claims::Issuer { iss: "".into() },
sub: claims::Subject { sub: "".into() },
nbf: claims::NotBefore { nbf: 0 },
exp: claims::Expiration { exp: 1 },
cnf: claims::Confirm::new(signer.public_key()),
};
cwt::issue_at(
&claims,
signer,
darkbio_trust::CRYPTO_DOMAIN_DEVICE_ATTESTATION,
TIMESTAMP,
)
.unwrap()
}
pub fn frame(packet: &[u8]) -> Vec<u8> {
let mut buf = vec![0u8; cobs::encode_buffer(packet.len())];
let n = cobs::encode(packet, &mut buf).unwrap();
buf.truncate(n);
buf.push(0x00);
buf
}
pub fn unframe(frame: &[u8]) -> Vec<u8> {
let mut buf = vec![0u8; cobs::decode_buffer(frame.len())];
let n = cobs::decode(frame, &mut buf).expect("side under test wrote an undecodable frame");
buf.truncate(n);
buf
}
pub fn would_block() -> io::Error {
io::ErrorKind::WouldBlock.into()
}
pub type Recorder = Rc<RefCell<Option<Vector>>>;
pub fn trace(recorder: &Recorder, event: impl FnOnce() -> Event) {
if let Some(vector) = recorder.borrow_mut().as_mut() {
vector.log(event());
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
pub enum CutPoint {
Start,
Middle(u16),
Delimiter,
Flush,
}
#[derive(Clone, Default)]
pub struct Outbox {
bytes: Rc<RefCell<Vec<u8>>>,
broken: Rc<Cell<bool>>,
cut: Rc<Cell<Option<CutPoint>>>,
flush_fails: Rc<Cell<bool>>,
recorder: Recorder, }
impl Outbox {
pub fn take_frames(&self) -> Vec<Vec<u8>> {
let mut bytes = self.bytes.borrow_mut();
let mut frames: Vec<Vec<u8>> = bytes.split(|&b| b == 0).map(<[u8]>::to_vec).collect();
let tail = frames.pop().expect("split yields at least one piece");
*bytes = tail;
frames
}
pub fn has_tail(&self) -> bool {
!self.bytes.borrow().is_empty()
}
pub fn set_broken(&self, broken: bool) {
self.broken.set(broken);
}
pub fn set_cut(&self, point: CutPoint) {
self.cut.set(Some(point));
}
fn accept(&self, buf: &[u8]) -> (usize, bool) {
if let Some(point) = self.cut.get() {
let accepted = match point {
CutPoint::Start => Some(0),
CutPoint::Middle(n) => (buf.len() > 2).then(|| 1 + n as usize % (buf.len() - 2)),
CutPoint::Delimiter => (buf.len() > 1).then(|| buf.len() - 1),
CutPoint::Flush => (buf.len() > 1).then_some(buf.len()),
};
if let Some(accepted) = accepted {
self.cut.set(None);
if point == CutPoint::Flush {
self.flush_fails.set(true);
return (accepted, false);
}
return (accepted, true);
}
}
if self.broken.get() {
return (0, true);
}
(buf.len(), false)
}
}
impl Write for Outbox {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let (accepted, failed) = self.accept(buf);
self.bytes.borrow_mut().extend_from_slice(&buf[..accepted]);
trace(&self.recorder, || Event::Write {
bytes: buf[..accepted].to_vec(),
failed,
});
match failed {
true => Err(io::ErrorKind::BrokenPipe.into()),
false => Ok(accepted),
}
}
fn flush(&mut self) -> io::Result<()> {
match self.flush_fails.replace(false) {
true => {
trace(&self.recorder, || Event::FlushFailed);
Err(io::ErrorKind::BrokenPipe.into())
}
false => Ok(()),
}
}
}