Identity Architecture

This document describes Commonplace's federated identity system, which provides cryptographic identity verification for both users and servers in a federated environment.

Overview

Commonplace uses DNS as the foundation for identity verification, enabling global identity resolution and trust establishment between servers. This approach allows for decentralized identity management while maintaining strong cryptographic security.

Core Identity Types

User Identity

Users are identified using an email-like format: username@server.domain.com

pub struct UserIdentity {
    pub username: String,
    pub server_domain: String,
    pub public_key: PublicKey,
    pub display_name: Option<String>,
    pub email: Option<String>,
    pub created_at: SystemTime,
}

Key Properties:

  • Global Uniqueness: No two users can have the same username@server.domain.com
  • Server Binding: Users are bound to their home server's domain (identity domain, not connection host)
  • Cryptographic Identity: Each user has an Ed25519 key pair
  • Portability: Users can migrate between servers while maintaining identity, although mechanisms for doing this are not yet described, since the domain portion of a user's identity might need to change.

Server Identity

Servers are identified by their domain name and verified through DNS:

pub struct ServerIdentity {
    pub domain: String,
    pub public_key: PublicKey,
    pub private_key: PrivateKey,
}

pub struct ServerEndpoint {
    pub host: String,
    pub port: u16,
    pub priority: u16,
    pub weight: u16,
    pub expected_key: PublicKey,
}

Key Properties:

  • DNS Verification: Public key published in DNS TXT record
  • Service Discovery: Connection details published in DNS SRV records
  • Flexible Deployment: Servers can run on any host while maintaining domain identity
  • Federation Ready: Enables server-to-server trust establishment
  • Rotation Support: Keys can be rotated with DNS updates
  • Redundancy: Built-in support for multiple servers with failover and load balancing

In future, we may need to enable direct server relationship establishment without DNS; the DNS mechanism allows for decentralised discovery but should not obviate explicitly-added connections.

DNS Integration

Commonplace uses a two-record DNS approach that separates service discovery from identity verification:

Server DNS Records

Service Discovery (SRV Records): Servers publish connection details through DNS SRV records:

_commonplace._tcp.server.domain.com. 300 IN SRV 0 5 12000 actual-host.example.com.

SRV Record Format:

  • _commonplace._tcp: Service and protocol identifiers
  • server.domain.com: Identity domain
  • 0: Priority (lower = higher priority)
  • 5: Weight (for load balancing among same priority)
  • 12000: Port number
  • actual-host.example.com.: Target hostname to connect to

Identity Verification (TXT Records): Servers publish their cryptographic identity through DNS TXT records:

_commonplace.server.domain.com. TXT "v=1;k=<base64-encoded-public-key>"

TXT Record Format:

  • v=1: Protocol version
  • k=<key>: Base64-encoded Ed25519 public key

DNS Discovery Process

  1. Service Discovery: Query _commonplace._tcp.<domain> SRV record(s)
  2. Identity Verification: Query _commonplace.<domain> TXT record
  3. Connection Establishment: Connect to SRV target(s) in priority/weight order
  4. Identity Verification: Verify server signatures against TXT public key
  5. Caching: Cache both SRV and TXT records with appropriate TTL

Multiple Server Support

SRV records naturally support multiple servers for redundancy and load balancing:

Failover Configuration:

_commonplace._tcp.myserver.com. 300 IN SRV 0 5 12000 primary.hosting.com.
_commonplace._tcp.myserver.com. 300 IN SRV 1 5 12000 backup.hosting.com.

Load Balancing Configuration:

_commonplace._tcp.myserver.com. 300 IN SRV 0 10 12000 server1.hosting.com.
_commonplace._tcp.myserver.com. 300 IN SRV 0 10 12000 server2.hosting.com.

Complex Deployment Example:

; Identity domain: company.com, but servers run elsewhere
_commonplace._tcp.company.com. 300 IN SRV 0 10 12000 lb1.hosting-provider.net.
_commonplace._tcp.company.com. 300 IN SRV 0 10 12000 lb2.hosting-provider.net.
_commonplace._tcp.company.com. 300 IN SRV 1 5  12000 backup.company.com.

; Single identity key for all servers
_commonplace.company.com. TXT "v=1;k=ABC123..."

Implementation Status: DNS publishing planned; verification logic designed

Identity Binding

User Registration Process

When a user registers with a server, an identity binding is created:

pub struct IdentityBinding {
    pub username: String,
    pub server_domain: String,
    pub public_key: PublicKey,
    pub server_signature: Signature,
    pub created_at: SystemTime,
}

Binding Creation:

  1. User generates Ed25519 key pair
  2. User submits registration request with public key
  3. Server creates binding signed with server's private key
  4. Binding stored in user's identity record

Identity Verification

Other servers can verify user identities through:

  1. DNS Lookup: Verify the user's home server identity
  2. Binding Verification: Check server signature on identity binding
  3. User Verification: Verify user signatures against bound public key

Cryptographic Operations

Key Generation

Server Keys:

impl ServerIdentity {
    pub fn generate_for_domain(domain: &str) -> Self {
        let keypair = Ed25519KeyPair::generate();
        ServerIdentity {
            domain: domain.to_string(),
            public_key: keypair.public_key(),
            private_key: keypair.private_key(),
            port: None,
            path: None,
        }
    }
}

User Keys:

impl UserCredentials {
    pub fn generate(username: &str, server_domain: &str) -> Self {
        let keypair = Ed25519KeyPair::generate();
        let identity = UserIdentity {
            username: username.to_string(),
            server_domain: server_domain.to_string(),
            public_key: keypair.public_key(),
            display_name: None,
            email: None,
            created_at: SystemTime::now(),
        };
        UserCredentials {
            identity,
            private_key: keypair.private_key(),
        }
    }
}

Digital Signatures

All identity operations use Ed25519 signatures:

User Signatures:

  • Authentication challenges
  • Content signing for integrity
  • Share request authorization

Server Signatures:

  • Identity binding creation
  • Federation protocol messages
  • Cross-server verification

Security Considerations

DNS Security

Current Approach:

  • Standard DNS with SRV and TXT record verification
  • Separate caching for service discovery (SRV) and identity verification (TXT)
  • Regular re-verification of server keys and endpoints
  • Connection attempts to multiple endpoints for redundancy

Future Enhancements:

  • DNSSEC validation for enhanced security
  • DNS-over-HTTPS for privacy
  • Certificate transparency integration
  • SRV record validation to prevent redirection attacks

CLARIFY: DNSSEC implementation timeline and requirements

Key Management

Server Key Security:

  • Private keys stored securely on server
  • Key rotation procedures through DNS updates
  • Backup and recovery processes

User Key Security:

  • Private keys stored locally by client
  • Secure key backup and recovery
  • Multi-device key synchronization (planned)

Attack Vectors

DNS Spoofing:

  • Mitigated by cryptographic signature verification against TXT record
  • SRV record spoofing mitigated by identity verification step
  • Enhanced by DNSSEC (planned)
  • Connection pinning for known servers
  • Multiple endpoint verification reduces single point of failure

Key Compromise:

  • Server key rotation through DNS
  • User key rotation through re-registration
  • Revocation mechanisms (planned)

Implementation Details

Server Discovery and Connection

pub async fn discover_server(domain: &str) -> Result<Vec<ServerEndpoint>> {
    // 1. Get connection details from SRV record
    let srv_records = dns_lookup_srv(&format!("_commonplace._tcp.{}", domain)).await?;
    
    // 2. Get identity verification key from TXT record  
    let txt_record = dns_lookup_txt(&format!("_commonplace.{}", domain)).await?;
    let server_key = parse_commonplace_txt_record(&txt_record)?;
    
    // 3. Convert SRV records to connection endpoints
    let mut endpoints = Vec::new();
    for srv in srv_records {
        endpoints.push(ServerEndpoint {
            host: srv.target,
            port: srv.port,
            priority: srv.priority,
            weight: srv.weight,
            expected_key: server_key.clone(),
        });
    }
    
    // 4. Sort by priority, then randomize by weight for load balancing
    endpoints.sort_by_key(|e| (e.priority, rand::random::<u32>() % (e.weight + 1)));
    Ok(endpoints)
}

pub async fn connect_to_server(domain: &str) -> Result<ServerConnection> {
    let endpoints = discover_server(domain).await?;
    
    // Try endpoints in priority order
    for endpoint in endpoints {
        match try_connect(&endpoint.host, endpoint.port).await {
            Ok(conn) => {
                // Verify the server's identity matches expected key
                if verify_server_identity(&conn, &endpoint.expected_key).await? {
                    return Ok(conn);
                }
            }
            Err(e) => {
                log::warn!("Failed to connect to {}:{}: {}", endpoint.host, endpoint.port, e);
                continue; // Try next endpoint
            }
        }
    }
    
    Err("All server endpoints failed".into())
}

Server Identity Management

impl ServerIdentity {
    pub fn dns_txt_record_value(&self) -> String {
        format!("v=1;k={}", base64::encode(&self.public_key))
    }
    
    pub fn dns_srv_record_value(&self, target_host: &str, port: u16, priority: u16, weight: u16) -> String {
        format!("{} {} {} {}", priority, weight, port, target_host)
    }
    
    pub fn sign(&self, message: &[u8]) -> Signature {
        self.private_key.sign(message)
    }
}

User Identity Operations

impl UserIdentity {
    pub fn full_address(&self) -> String {
        format!("{}@{}", self.username, self.server_domain)
    }
    
    pub fn global_id(&self) -> String {
        // Consistent global identifier for user
        let mut hasher = Sha256::new();
        hasher.update(self.username.as_bytes());
        hasher.update(b"@");
        hasher.update(self.server_domain.as_bytes());
        hasher.update(&self.public_key.as_bytes());
        base64::encode(hasher.finalize())
    }
}

Identity Binding Verification

impl IdentityBinding {
    pub fn verify(&self, server_public_key: &PublicKey) -> Result<(), VerificationError> {
        let message = self.signing_message();
        server_public_key.verify(&message, &self.server_signature)
    }
    
    fn signing_message(&self) -> Vec<u8> {
        let mut message = Vec::new();
        message.extend_from_slice(self.username.as_bytes());
        message.extend_from_slice(b"@");
        message.extend_from_slice(self.server_domain.as_bytes());
        message.extend_from_slice(&self.public_key.as_bytes());
        message.extend_from_slice(&self.created_at.duration_since(UNIX_EPOCH).unwrap().as_secs().to_be_bytes());
        message
    }
}

Migration Considerations

No existing servers or users to migrate. However, cross-server user migration (see below) is likely to be necessary in future.

Cross-Server Migration

User Migration Process (Planned):

  1. Export user data from source server
  2. Register with destination server
  3. Import data to new server
  4. Update identity bindings
  5. Notify contacts of migration

CLARIFY: Migration protocol and data portability standards

Future Enhancements

Advanced DNS Features

DNSSEC Integration:

  • Cryptographic validation of DNS records
  • Protection against DNS spoofing attacks
  • Enhanced trust in service discovery

Dynamic Service Discovery:

  • Health-check based SRV record updates
  • Automatic failover through DNS
  • Geographic load balancing with multiple SRV records

Service-Specific Endpoints:

; Different services on different hosts
_commonplace._tcp.chat.company.com. 300 IN SRV 0 5 12000 chat.internal.
_commonplace._tcp.files.company.com. 300 IN SRV 0 5 12001 files.internal.
; Shared identity verification
_commonplace.company.com. TXT "v=1;k=<shared-key>"

Advanced Identity Features

Multi-Device Identity:

  • Synchronized keys across devices
  • Device-specific sub-keys
  • Revocation of compromised devices
  • Per-device SRV records for direct device connections

Identity Attestation:

  • Third-party identity verification
  • Web-of-trust mechanisms
  • Integration with existing identity providers
  • Cross-domain identity verification via DNS

Privacy Features:

  • Anonymous identity options
  • Pseudonymous interactions
  • Identity compartmentalization
  • DNS-based privacy-preserving discovery

Protocol Extensions

Identity Discovery:

  • Public identity directories via DNS
  • Friend-of-friend discovery through federated DNS
  • Social graph integration with DNS-based hints

Advanced Verification:

  • Multi-factor authentication
  • Hardware key support
  • Biometric binding
  • DNS-based certificate transparency logs

Deployment Flexibility:

  • Container-based deployments with dynamic DNS updates
  • CDN integration for global server distribution
  • Hybrid cloud deployments with DNS service discovery

Implementation Status

  • Identity Structures: Designed and specified
  • DNS Architecture: SRV + TXT record approach designed
  • DNS Integration: SRV/TXT lookup implementation planned
  • Server Discovery: Multi-endpoint connection logic planned
  • Registration Flow: Implementation planned
  • Verification Logic: Implementation planned
  • Key Management: Implementation planned
  • DNS Record Management: Tooling for DNS setup possible

Related Documents