Skip to main content

darkbio_wire/
lib.rs

1// wire-rs: encrypted protocol between Ark and host
2// Copyright 2025 Dark Bio AG. All rights reserved.
3
4// Allow excluding test code from coverage measurements on nightly
5#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
6// Pull in the README as the package doc
7#![doc = include_str!("../README.md")]
8
9pub mod protocol;
10
11mod client;
12mod framing;
13mod handshake;
14mod server;
15mod session;
16
17#[cfg(any(test, feature = "fuzz"))]
18#[doc(hidden)]
19#[cfg_attr(coverage_nightly, coverage(off))]
20pub mod mock;
21
22pub use client::{Client, Roots, Verifier};
23pub use protocol::{ArkToHost, HostToArk};
24pub use server::{Attestation, Attester, Server};
25
26use std::io;
27
28/// Maximum limit for a frame size, above which it will be discarded from the
29/// wire protocol.
30pub const MAX_FRAME_SIZE: usize = 2 * 1024 * 1024;
31
32/// Largest protobuf message the wire carries, being what still fits a frame
33/// after the session's sealing and the COBS framing overheads are added.
34pub const MAX_MESSAGE_SIZE: usize = {
35    let mut size = MAX_FRAME_SIZE;
36    while darkbio_cobs::encode_buffer(size + session::Session::SEAL_OVERHEAD) > MAX_FRAME_SIZE {
37        size -= 1;
38    }
39    size
40};
41
42/// Domain separator for the COSE envelopes of the handshake, sealing the server's
43/// hello and the client's ack (the client's hello is plain CBOR). It binds their
44/// signatures and encryption to the wire, so a handshake signed by the server's
45/// identity key cannot be replayed into other protocols using the same key.
46pub(crate) const CRYPTO_DOMAIN_WIRE: &[u8] = b"wire-v1";
47
48/// HPKE info string for the ark-to-host encryption context of an established
49/// session (message traffic after the handshake, not the handshake itself).
50pub(crate) const CRYPTO_DOMAIN_WIRE_ARK_TO_HOST: &[u8] = b"wire-v1:ark-to-host";
51
52/// HPKE info string for the host-to-ark encryption context of an established
53/// session (message traffic after the handshake, not the handshake itself).
54pub(crate) const CRYPTO_DOMAIN_WIRE_HOST_TO_ARK: &[u8] = b"wire-v1:host-to-ark";
55
56/// Things that can go wrong in the wire transport.
57#[derive(Debug, thiserror::Error)]
58// The mocks name the variants in their transcripts
59#[cfg_attr(
60    all(any(test, feature = "fuzz"), not(docsrs)),
61    derive(strum::IntoStaticStr)
62)]
63pub enum Error {
64    #[error("wire packet too large: {0} bytes, max {MAX_MESSAGE_SIZE} bytes")]
65    PacketTooLarge(usize),
66
67    #[error("wire packet encode failed: {0}")]
68    PacketEncodingFailed(prost::EncodeError),
69
70    #[error("wire packet decode failed: {0}")]
71    PacketDecodingFailed(prost::DecodeError),
72
73    #[error("wire frame too large: {0} bytes, max {MAX_FRAME_SIZE} bytes")]
74    FrameTooLarge(usize),
75
76    #[error("wire frame decode failed: {0}")]
77    FrameDecodingFailed(darkbio_cobs::DecodeError),
78
79    #[error("wire send failed: {0}")]
80    SendFailed(io::Error),
81
82    #[error("wire receive failed: {0}")]
83    RecvFailed(io::Error),
84
85    #[error("wire terminated")]
86    Terminated,
87
88    #[error("wire session reset by the server")]
89    SessionReset,
90
91    #[error("attestation is not for a hardware or emulator")]
92    InvalidAttestation,
93
94    #[error("wire handshake failed: {0}")]
95    HandshakeFailed(String),
96
97    #[error("wire encryption failed: {0}")]
98    EncryptionFailed(String),
99}
100
101#[cfg(test)]
102#[cfg_attr(coverage_nightly, coverage(off))]
103pub(crate) mod testing {
104    use std::sync::Once;
105
106    static INIT: Once = Once::new();
107
108    // init_tracing sets up a test logger to push log messages to stderr.
109    pub fn init_tracing() {
110        INIT.call_once(|| {
111            tracing_subscriber::fmt()
112                .with_env_filter(
113                    tracing_subscriber::EnvFilter::from_default_env()
114                        .add_directive(tracing::Level::TRACE.into()),
115                )
116                .with_ansi(true)
117                .with_test_writer()
118                .init();
119        });
120    }
121}