Module version

Module version 

Source
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 communication
  • zoep - Peer-to-peer protocol for direct client communication
  • zoem - 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:

§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 ProtocolVersion struct
  • 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§

ClientProtocolConfig
Client protocol configuration - defines what versions the client supports
ProtocolVersion
Protocol version information combining variant and semantic version
ServerProtocolConfig
Server protocol configuration - defines what requirements the server has
Version
SemVer version as defined by https://semver.org.
VersionReq
SemVer version requirement describing the intersection of some version comparators, such as >=1.2.3, <1.8.

Enums§

ProtocolVariant
Protocol variants supported by the Zoe wire protocol
ProtocolVersionError
Errors that can occur during protocol version negotiation

Statics§

DEFAULT_PROTOCOL_VERSION 🔒
DEFAULT_PROTOCOL_VERSION_REQ 🔒

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