Skip to content
Open
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
1 change: 0 additions & 1 deletion consumer-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ workspace = true
[dependencies]
tightbeam = { package = "tightbeam-rs", path = "../tightbeam", default-features = false, features = [
"std",
"derive",
"builder",
"crypto",
"digest",
Expand Down
2 changes: 1 addition & 1 deletion scripts/test_features.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ echo "[4/16] Check: Transport Full + TCP + Async"
cargo check --package tightbeam-rs --no-default-features --features "std,transport-cms,transport-ecies,tcp,tokio,testing"

echo "[5/16] Check: Transport CMS + Derive"
cargo check --package tightbeam-rs --no-default-features --features "std,transport-cms,derive,testing"
cargo check --package tightbeam-rs --no-default-features --features "std,transport-cms,testing"

echo "[6/16] Check: Testing CSP/FDR"
cargo check --package tightbeam-rs --no-default-features --features "std,transport-cms,testing,testing-csp,testing-fdr"
Expand Down
6 changes: 0 additions & 6 deletions tightbeam-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,3 @@ workspace = true
proc-macro2 = { workspace = true }
quote = { workspace = true }
syn = { workspace = true }

[features]
aead = []
digest = []
signature = []
compress = []
70 changes: 33 additions & 37 deletions tightbeam-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,30 @@ pub fn derive_beamable(input: TokenStream) -> TokenStream {
expand_beamable(&input).unwrap_or_else(syn::Error::into_compile_error).into()
}

/// A compile error that fires when a `#[beam]` requirement names a tightbeam
/// feature the build disables.
///
/// The check runs through tightbeam's `shim` macro, so tightbeam's own feature
/// state decides it. This crate carries no copy of tightbeam's features.
fn feature_check(
name: &syn::Ident,
shim: impl AsRef<str>,
requirement: impl AsRef<str>,
feature: impl AsRef<str>,
) -> proc_macro2::TokenStream {
let shim = syn::Ident::new(shim.as_ref(), name.span());
let message = format!(
"Message type `{name}` is marked as {} but the `{feature}` feature is not enabled. \
Enable the feature in Cargo.toml: features = [\"{feature}\"]",
requirement.as_ref(),
feature = feature.as_ref(),
);

quote! {
::tightbeam::#shim! { else { compile_error!(#message); } }
}
}

fn expand_beamable(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
let name = &input.ident;

Expand Down Expand Up @@ -226,45 +250,17 @@ fn expand_beamable(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream>
let final_frame_integrity = frame_integrity;

let mut feature_checks = Vec::new();

if final_confidential && !cfg!(feature = "aead") {
feature_checks.push(quote! {
compile_error!(concat!(
"Message type `", stringify!(#name), "` is marked as confidential ",
"but the `aead` feature is not enabled. ",
"Enable the feature in Cargo.toml: features = [\"aead\"]"
));
});
if final_confidential {
feature_checks.push(feature_check(name, "__tb_if_aead", "confidential", "aead"));
}

if final_nonrep && !cfg!(feature = "signature") {
feature_checks.push(quote! {
compile_error!(concat!(
"Message type `", stringify!(#name), "` is marked as non-repudiable ",
"but the `signature` feature is not enabled. ",
"Enable the feature in Cargo.toml: features = [\"signature\"]"
));
});
if final_nonrep {
feature_checks.push(feature_check(name, "__tb_if_signature", "non-repudiable", "signature"));
}

if compressed && !cfg!(feature = "compress") {
feature_checks.push(quote! {
compile_error!(concat!(
"Message type `", stringify!(#name), "` is marked as compressed ",
"but the `compress` feature is not enabled. ",
"Enable the feature in Cargo.toml: features = [\"compress\"]"
));
});
if compressed {
feature_checks.push(feature_check(name, "__tb_if_compress", "compressed", "compress"));
}

if (final_message_integrity || final_frame_integrity) && !cfg!(feature = "digest") {
feature_checks.push(quote! {
compile_error!(concat!(
"Message type `", stringify!(#name), "` is marked as requiring message integrity ",
"but the `digest` feature is not enabled. ",
"Enable the feature in Cargo.toml: features = [\"digest\"]"
));
});
if final_message_integrity || final_frame_integrity {
feature_checks.push(feature_check(name, "__tb_if_digest", "requiring message integrity", "digest"));
}

let min_version_value = if let Some(version) = final_min_version {
Expand All @@ -290,7 +286,7 @@ fn expand_beamable(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream>
};

// Generate checker trait implementations for compile-time OID validation
// When HAS_PROFILE = true: generates impls ONLY for the matching OID type from the profile (compile-time enforcement)
// When HAS_PROFILE = true: generates impls ONLY for the matching OID type from the profile
// When HAS_PROFILE = false: generates generic impls for all OID types (no enforcement, allows any)
// All types using #[derive(Beamable)] get these impls - types not using derive must implement manually
let oid_validation_helpers = if let Some(profile_ty) = &profile_type {
Expand Down
18 changes: 4 additions & 14 deletions tightbeam/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ full = [
"kdf",
"ecies",
"ecdh",
"derive",
"tokio",
"futures",
"constants",
Expand All @@ -126,7 +125,7 @@ full = [
# Core features
constants = ["hex"]
crypto = ["random", "dep:crypto-common", "zeroize"]
builder = ["derive", "x509-cert/builder", "crypto"]
builder = ["x509-cert/builder", "crypto"]
policy = []
router = []
transport = [
Expand All @@ -139,7 +138,7 @@ transport = [
"kdf",
"ecdh",
]
compress = ["tightbeam-derive/compress"]
compress = []
transport-policy = ["transport", "policy"]
transport-multiplex = ["transport", "std", "futures", "futures/std"]
# UNSTABLE: PQXDH prekey/kdf-chain/hybrid-KEM primitives.
Expand All @@ -152,7 +151,6 @@ colony = [
"builder",
"policy",
"router",
"derive",
"transport",
"transport-ecies",
"transport-multiplex",
Expand All @@ -170,11 +168,9 @@ testing-schedulability = ["testing", "testing-timing"]
testing-fault = ["testing", "testing-fdr"]
testing-fmea = ["testing", "testing-fault", "instrument"]
testing-fuzz = ["testing", "testing-csp", "dep:afl"]
# Property-based tests over the wire types. Off by default: the strategies
# only compile when a consumer asks for them.
testing-property = ["testing", "dep:proptest"]
testing-fuzz-ijon = ["testing-fuzz"]
instrument = ["std", "sha3", "digest", "derive"]
instrument = ["std", "sha3", "digest"]
logging = []

# TODO
Expand All @@ -188,7 +184,6 @@ aead = [
"dep:aead",
"dep:ecdsa",
"dep:crypto-common",
"tightbeam-derive/aead",
"aead/rand_core",
"dep:aes",
"dep:aes-kw",
Expand All @@ -203,12 +198,11 @@ signature = [
"dep:ecdsa",
"ecdsa/verifying",
"ecdsa/pem",
"tightbeam-derive/signature",
"dep:signature",
"cms/signature",
"x509-cert/signature",
]
digest = ["crypto", "dep:digest", "tightbeam-derive/digest", "sha3"]
digest = ["crypto", "dep:digest", "sha3"]
x509 = ["crypto", "dep:x509-cert", "ecdsa/pem", "digest"]
kdf = ["crypto", "random", "zeroize", "digest", "dep:hkdf"]
ecies = ["crypto", "kdf", "aead", "k256/ecdh", "secp256k1", "sha3"]
Expand Down Expand Up @@ -255,10 +249,6 @@ transport-ecies = [
"ecdh",
]

# Gates the `Beamable` and `Flaggable` re-exports and the generated error and
# URN implementations. `builder` and `instrument` both select it.
derive = []

# Standard library support
std = [
"der/std",
Expand Down
69 changes: 0 additions & 69 deletions tightbeam/src/builder/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,6 @@ mod tests {
// V1 is the first version whose metadata carries integrity info.
// `MetadataBuilder::build` rejects V0 with `message_integrity`.
#[test]
#[cfg(feature = "derive")]
fn test_compose_macro() -> Result<()> {
let message = TestMessage::sample(None);
let frame = compose! {
Expand Down Expand Up @@ -1038,82 +1037,30 @@ mod tests {
macro_rules! test_msg_struct {
// BasicMessage: (false, false, false, false, V0)
(false, false, false, false, V0) => {
#[cfg(feature = "derive")]
#[derive($crate::Beamable, Clone, Debug, PartialEq, der::Sequence)]
#[beam(min_version = "V0")]
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
#[derive(Clone, Debug, PartialEq, der::Sequence)]
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
impl $crate::Message for TestMsg {
const MUST_BE_CONFIDENTIAL: bool = false;
const MUST_BE_NON_REPUDIABLE: bool = false;
const MUST_BE_COMPRESSED: bool = false;
const MUST_BE_PRIORITIZED: bool = false;
const MUST_HAVE_MESSAGE_INTEGRITY: bool = false;
const MUST_HAVE_FRAME_INTEGRITY: bool = false;
const MIN_VERSION: Version = Version::V0;
type Profile = $crate::crypto::profiles::TightbeamProfile;
}
};
// ConfidentialMessage: (true, false, false, false, V1)
(true, false, false, false, V1) => {
#[cfg(feature = "derive")]
#[derive($crate::Beamable, Clone, Debug, PartialEq, der::Sequence)]
#[beam(confidential, min_version = "V1")]
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
#[derive(Clone, Debug, PartialEq, der::Sequence)]
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
impl $crate::Message for TestMsg {
const MUST_BE_CONFIDENTIAL: bool = true;
const MUST_BE_NON_REPUDIABLE: bool = false;
const MUST_BE_COMPRESSED: bool = false;
const MUST_BE_PRIORITIZED: bool = false;
const MUST_HAVE_MESSAGE_INTEGRITY: bool = false;
const MUST_HAVE_FRAME_INTEGRITY: bool = false;
const MIN_VERSION: Version = Version::V1;
type Profile = $crate::crypto::profiles::TightbeamProfile;
}
};
// NonrepudiableMessage: (false, true, false, false, V1)
(false, true, false, false, V1) => {
#[cfg(feature = "derive")]
#[derive($crate::Beamable, Clone, Debug, PartialEq, der::Sequence)]
#[beam(nonrepudiable, min_version = "V1")]
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
#[derive(Clone, Debug, PartialEq, der::Sequence)]
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
impl $crate::Message for TestMsg {
const MUST_BE_CONFIDENTIAL: bool = false;
const MUST_BE_NON_REPUDIABLE: bool = true;
const MUST_BE_COMPRESSED: bool = false;
const MUST_BE_PRIORITIZED: bool = false;
const MUST_HAVE_MESSAGE_INTEGRITY: bool = false;
const MUST_HAVE_FRAME_INTEGRITY: bool = false;
const MIN_VERSION: Version = Version::V1;
type Profile = $crate::crypto::profiles::TightbeamProfile;
}
};
// FullSecurityMessage: (true, true, true, true, V2)
(true, true, true, true, V2) => {
#[cfg(feature = "derive")]
#[derive($crate::Beamable, Clone, Debug, PartialEq, der::Sequence)]
#[beam(
confidential,
Expand All @@ -1125,22 +1072,6 @@ mod tests {
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
#[derive(Clone, Debug, PartialEq, der::Sequence)]
struct TestMsg {
content: String,
}
#[cfg(not(feature = "derive"))]
impl $crate::Message for TestMsg {
const MUST_BE_CONFIDENTIAL: bool = true;
const MUST_BE_NON_REPUDIABLE: bool = true;
const MUST_BE_COMPRESSED: bool = false;
const MUST_BE_PRIORITIZED: bool = false;
const MUST_HAVE_MESSAGE_INTEGRITY: bool = true;
const MUST_HAVE_FRAME_INTEGRITY: bool = true;
const MIN_VERSION: Version = Version::V2;
type Profile = $crate::crypto::profiles::TightbeamProfile;
}
};
}

Expand Down
9 changes: 4 additions & 5 deletions tightbeam/src/colony/worker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,13 @@ pub struct WorkerRequest<I: Send, O> {
pub trace: Arc<TraceCollector>,
}

#[cfg_attr(feature = "derive", derive(Errorizable))]
#[derive(Debug)]
#[derive(Errorizable, Debug)]
pub enum WorkerRelayError {
#[cfg_attr(feature = "derive", error("Worker queue closed"))]
#[error("Worker queue closed")]
QueueClosed,
#[cfg_attr(feature = "derive", error("Worker response channel dropped"))]
#[error("Worker response channel dropped")]
ResponseDropped,
#[cfg_attr(feature = "derive", error("Message rejected with status {:?}"))]
#[error("Message rejected with status {:?}")]
Rejected(TransitStatus),
}

Expand Down
4 changes: 0 additions & 4 deletions tightbeam/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,30 +429,26 @@ mod tests {
} => EncryptedContentInfo,
}

#[cfg(feature = "derive")]
#[derive(Beamable, Clone, Debug, PartialEq, der::Sequence)]
#[beam(profile = 1)]
struct NumericProfileMessage {
id: u64,
data: String,
}

#[cfg(feature = "derive")]
#[derive(Beamable, Clone, Debug, PartialEq, der::Sequence)]
#[beam(profile(crate::crypto::profiles::TightbeamProfile))]
struct TypeProfileMessage {
id: u64,
data: String,
}

#[cfg(feature = "derive")]
#[derive(Beamable, Clone, Debug, PartialEq, der::Sequence)]
struct NoProfileMessage {
id: u64,
data: String,
}

#[cfg(feature = "derive")]
#[test]
#[allow(clippy::assertions_on_constants)]
fn test_profile_types() {
Expand Down
4 changes: 1 addition & 3 deletions tightbeam/src/crypto/profiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ use crate::der::oid::AssociatedOid;
use crate::spki::AlgorithmIdentifierOwned;
#[cfg(feature = "transport")]
use crate::transport::handshake::HandshakeError;
#[cfg(feature = "derive")]
use crate::Beamable;
use crate::Errorizable;
/// Macro to generate key wrapper implementations.
Expand Down Expand Up @@ -124,8 +123,7 @@ impl AeadKeySize for crate::crypto::aead::Aes256GcmOid {
///
/// Every field is `Option`: `None` uniformly means "algorithm not part of
/// this profile" (feature disabled on the producing side).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Sequence)]
#[cfg_attr(feature = "derive", derive(Beamable))]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Sequence, Beamable)]
pub struct SecurityProfileDesc {
pub digest: Option<ObjectIdentifier>,
pub aead: Option<ObjectIdentifier>,
Expand Down
1 change: 0 additions & 1 deletion tightbeam/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ pub use tightbeam_derive::Errorizable;

#[cfg(feature = "hex")]
pub use hex_literal::hex;
#[cfg(feature = "derive")]
pub use tightbeam_derive::{Beamable, Flaggable};
#[cfg(feature = "time")]
pub use time;
Expand Down
Loading
Loading