Expand description
§Protocol Version Negotiation
This module provides semver-based protocol version negotiation with TLS certificate-embedded version information. The Zoe protocol supports multiple variants for different use cases:
zoer- Relay protocol for server-mediated communicationzoep- Peer-to-peer protocol for direct client communicationzoem- Mesh protocol for distributed network communication
§Protocol Negotiation Architecture
The protocol negotiation system combines TLS ALPN with certificate-embedded versioning to provide robust version compatibility checking with clear error reporting.
§Key Features
- Semantic Versioning: Full semver compatibility rules (major.minor.patch)
- Multiple Protocol Variants: Support for different protocol types
- Certificate-Embedded Negotiation: Version information embedded in X.509 extensions
- Clear Error Reporting: Specific errors for different failure modes
- Backward Compatibility: Graceful handling of version mismatches
§ALPN Data Format
Protocol versions are transmitted as postcard-serialized ProtocolVersion structs
in ALPN protocol fields, not as text strings. Each ALPN protocol entry contains
a binary-serialized ProtocolVersion { variant, version } structure.
§Version Compatibility Rules
- Major version: Breaking changes, no backward compatibility
- Minor version: New features, backward compatible
- Patch version: Bug fixes, fully compatible (not included in ALPN)
§Protocol Negotiation Flow
§1. Client Advertises Supported Versions
use zoe_wire_protocol::version::{ClientProtocolConfig, ProtocolVersion, ProtocolVariant};
use semver::Version;
let client_config = ClientProtocolConfig::new(vec![
ProtocolVersion::new(ProtocolVariant::V1, Version::new(1, 3, 0)),
ProtocolVersion::new(ProtocolVariant::V1, Version::new(1, 2, 0)),
ProtocolVersion::new(ProtocolVariant::V0, Version::new(0, 9, 0)),
]);
// Client sends these as postcard-serialized ALPN protocols during TLS handshake
let alpn_protocols: Vec<Vec<u8>> = client_config.alpn_protocols();
// Each Vec<u8> contains postcard::to_stdvec(&protocol_version).unwrap()§2. Server Negotiates Compatible Version
use zoe_wire_protocol::version::{ServerProtocolConfig, ProtocolVariant};
use semver::VersionReq;
let server_config = ServerProtocolConfig::new(vec![
(ProtocolVariant::V1, VersionReq::parse(">=1.2.0").unwrap()),
(ProtocolVariant::V0, VersionReq::parse(">=0.8.0").unwrap()),
]);
// Server finds highest compatible version
if let Some(negotiated) = server_config.negotiate_version(&client_config) {
println!("✅ Negotiated: {}", negotiated);
// Version embedded in TLS certificate
} else {
println!("❌ No compatible version found");
// Empty certificate extension sent
}§3. Client Validates Post-Connection
use zoe_wire_protocol::version::{validate_server_protocol_support, ProtocolVersionError};
match validate_server_protocol_support(&connection, &client_config) {
Ok(version) => {
println!("✅ Server supports: {}", version);
}
Err(ProtocolVersionError::ProtocolNotSupportedByServer) => {
println!("❌ Server returned empty protocol extension");
println!(" This means no client versions are supported by server");
}
Err(ProtocolVersionError::ProtocolMismatch) => {
println!("❌ Server negotiated unsupported version");
}
Err(e) => {
println!("❌ Validation error: {}", e);
}
}§Error Handling
The system provides specific error types for different failure scenarios:
ProtocolVersionError::ProtocolNotSupportedByServer: Server returned empty certificate extensionProtocolVersionError::ProtocolMismatch: Version negotiation disagreementProtocolVersionError::NoAlpnData: Missing certificate or extension dataProtocolVersionError::InvalidAlpnData: Malformed protocol data
§Certificate Extension Format
Protocol versions are embedded in X.509 certificate extensions:
- OID:
1.3.6.1.4.1.99999.1(Custom enterprise OID) - Format: Postcard-serialized
ProtocolVersionstruct - Serialization:
postcard::to_stdvec(&protocol_version)→Vec<u8> - Deserialization:
postcard::from_bytes::<ProtocolVersion>(&bytes)→ProtocolVersion - Empty Extension:
[](empty byte array) indicates no compatible protocol found
§Binary Format Details
The postcard format is a compact, deterministic binary serialization:
- Space-efficient: Smaller than JSON or other text formats
- Type-safe: Preserves Rust type information
- Deterministic: Same struct always produces same bytes
- Schema evolution: Handles version compatibility gracefully
§Integration Examples
§Automatic Client Integration
use zoe_client::RelayClient;
// RelayClient automatically performs protocol validation
match RelayClient::connect(server_addr, server_public_key).await {
Ok(client) => {
println!("✅ Connected with compatible protocol");
}
Err(ClientError::ProtocolError(msg)) => {
println!("❌ Protocol incompatibility: {}", msg);
// Handle version mismatch (upgrade client, contact admin, etc.)
}
Err(e) => {
println!("❌ Connection error: {}", e);
}
}§Manual Server Setup
use zoe_wire_protocol::connection::server::create_server_endpoint_with_protocols;
use zoe_wire_protocol::version::ServerProtocolConfig;
let server_config = ServerProtocolConfig::new(vec![
(ProtocolVariant::V1, VersionReq::parse(">=1.0.0").unwrap()),
]);
let server_endpoint = create_server_endpoint_with_protocols(
"127.0.0.1:0",
&server_keypair,
server_config,
).await?;Structs§
- Client
Protocol Config - Client protocol configuration - defines what versions the client supports
- Protocol
Version - Protocol version information combining variant and semantic version
- Server
Protocol Config - Server protocol configuration - defines what requirements the server has
- Version
- SemVer version as defined by https://semver.org.
- Version
Req - SemVer version requirement describing the intersection of some version
comparators, such as
>=1.2.3, <1.8.
Enums§
- Protocol
Variant - Protocol variants supported by the Zoe wire protocol
- Protocol
Version Error - Errors that can occur during protocol version negotiation
Statics§
Functions§
- extract_
protocol_ 🔒version_ from_ cert - Extract protocol version from certificate extension This reads the custom extension that contains the negotiated protocol version
- get_
negotiated_ protocol - Get the negotiated protocol from ALPN Returns the raw ALPN protocol bytes that were negotiated
- validate_
alpn_ negotiation - Validate that ALPN protocol negotiation succeeded This should be called by the client after connecting to ensure a protocol was negotiated
- validate_
server_ protocol_ support - Validate protocol compatibility after TLS connection establishment
- validate_
version_ compatibility - Validate that client and server negotiated to a compatible version This performs a full validation that both sides would agree on the same version