syntax = "proto3"; package arbiter; import "auth.proto"; message ClientRequest { oneof payload { arbiter.auth.ClientMessage auth_message = 1; CertRotationAck cert_rotation_ack = 2; } } message ClientResponse { oneof payload { arbiter.auth.ServerMessage auth_message = 1; CertRotationNotification cert_rotation_notification = 2; } } message UserAgentRequest { oneof payload { arbiter.auth.ClientMessage auth_message = 1; CertRotationAck cert_rotation_ack = 2; UnsealRequest unseal_request = 3; } } message UserAgentResponse { oneof payload { arbiter.auth.ServerMessage auth_message = 1; CertRotationNotification cert_rotation_notification = 2; UnsealResponse unseal_response = 3; } } message ServerInfo { string version = 1; bytes cert_public_key = 2; } // TLS Certificate Rotation Protocol message CertRotationNotification { // New public certificate (DER-encoded) bytes new_cert = 1; // Unix timestamp when rotation will be executed (if all ACKs received) int64 rotation_scheduled_at = 2; // Unix timestamp deadline for ACK (7 days from now) int64 ack_deadline = 3; // Rotation ID for tracking int32 rotation_id = 4; } message CertRotationAck { // Rotation ID (from CertRotationNotification) int32 rotation_id = 1; // Client public key for identification bytes client_public_key = 2; // Confirmation that client saved the new certificate bool cert_saved = 3; } // Vault Unseal Protocol (X25519 ECDH + ChaCha20Poly1305) message UnsealRequest { oneof payload { EphemeralKeyRequest ephemeral_key_request = 1; SealedPassword sealed_password = 2; } } message UnsealResponse { oneof payload { EphemeralKeyResponse ephemeral_key_response = 1; UnsealResult unseal_result = 2; } } message EphemeralKeyRequest {} message EphemeralKeyResponse { // Server's X25519 ephemeral public key (32 bytes) bytes server_pubkey = 1; // Unix timestamp when this key expires (60 seconds from generation) int64 expires_at = 2; } message SealedPassword { // Client's X25519 ephemeral public key (32 bytes) bytes client_pubkey = 1; // ChaCha20Poly1305 encrypted password (ciphertext + tag) bytes encrypted_password = 2; // 12-byte nonce for ChaCha20Poly1305 bytes nonce = 3; } message UnsealResult { // Whether unseal was successful bool success = 1; // Error message if unseal failed optional string error_message = 2; } service ArbiterService { rpc Client(stream ClientRequest) returns (stream ClientResponse); rpc UserAgent(stream UserAgentRequest) returns (stream UserAgentResponse); }