m³OS docs GitHub

Phase 43

SSH Server

An SSH server runs inside the OS, providing encrypted remote shell access. Users can connect from any standard SSH client (`ssh user@host`) with password or public key authentication. This replaces the telnet server for untrusted networks and is a major milestone: the OS is now a secure, networked, multi-user system.

Complete

Learning goal

Understand the SSH protocol: transport layer (encryption), user authentication layer, and connection layer (channels, sessions).

Category

infrastructure

Why this phase matters

An SSH server runs inside the OS, providing encrypted remote shell access. Users can connect from any standard SSH client (ssh user@host) with password or public key authentication. This replaces the telnet server for untrusted networks and is a major milestone: the OS is now a secure, networked, multi-user system.

How it works in m3OS

The roadmap entry defines the learning scope for this phase; a deeper implementation doc has not been matched yet.

How it builds on earlier phases

This phase builds on Async Executor and turns that foundation into SSH Server.

Implementation outline

  • Evaluate sunset crate: add dependency, verify it compiles for x86_64-m3os target.
  • Create userspace/sshd/ crate with basic TCP accept loop.
  • Generate Ed25519 host key on first boot, store at /etc/ssh/ssh_host_ed25519_key.
  • Implement sunset adapter: feed TCP bytes into sunset, write output back to socket.
  • Implement password authentication callback against /etc/shadow.
  • Implement session channel handling: PTY allocation, shell exec, data relay.
  • Implement public key authentication with ~/.ssh/authorized_keys.
  • (Deferred) Window-change and signal forwarding.
  • Add sshd to init’s startup sequence and initrd.
  • Test from host with ssh -p 2222 user@localhost.
  • Test multiple simultaneous SSH sessions.
  • Verify encryption by inspecting traffic.

Task progress snapshot

97 of 113 tracked tasks are complete.

Documentation targets

  • Documentation deliverables have not been listed yet.

Deferred follow-on work

  • SFTP / SCP file transfer
  • Port forwarding and tunneling
  • SSH client (for connecting from the OS to other machines)
  • Key agent
  • Certificate authentication
  • Connection rate limiting and brute-force protection
  • Privilege separation (sshd runs as a single process per session)
  • Multiple host key types (Ed25519 only)
  • Key re-exchange during long sessions

Source materials

Important code

Code spotlight cards

Code spotlight

Create `userspace/sshd/` crate

userspace/sshd/Cargo.toml L1-L11

pattern as telnetd (Phase 30). Separating the server from a library keeps the binary. Why it matters: A dedicated binary crate for the SSH server follows the same. Focus on `sshd` and `no_std` in `userspace/sshd/Cargo.toml` while you trace the snippet.

[package]
name = "sshd"
version = "0.1.0"
edition = "2024"

[[bin]]
name = "sshd"
path = "src/main.rs"

[dependencies]
syscall-lib = { path = "../syscall-lib", features = ["alloc"] }

Code spotlight

Verify sunset IO-less API compiles and runs in m3OS

userspace/sshd/src/main.rs See file

tested inside m3OS. This task confirms that creating a sunset server instance,. Why it matters: sunset is designed as an IO-less library, but it has not been. Focus on `sunset::Runner` and `Runner` in `userspace/sshd/src/main.rs` while you trace the snippet.

Code spotlight

Generate Ed25519 host key on first boot

userspace/sshd/src/host_key.rs L42-L65

first boot there is no key, so sshd must generate one using crypto-lib's Ed25519. Why it matters: The host key proves the server's identity during key exchange. On. Focus on `generate_host_key` and `crypto_lib::asymmetric::ed25519_keygen` in `userspace/sshd/src/host_key.rs` while you trace the snippet.

/// B.2: Generate a new Ed25519 host key and save to disk.
fn generate_host_key() -> Result<HostKey, ()> {
    let key = SignKey::generate(KeyType::Ed25519, None).map_err(|_| ())?;

    // Extract the 32-byte seed from the key.
    let seed = match &key {
        SignKey::Ed25519(k) => k.to_bytes(),
        _ => return Err(()),
    };

    // Write private key seed (mode 0600).
    let fd = open(HOST_KEY_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0o600);
    if fd < 0 {
        write_str(STDOUT_FILENO, "sshd: cannot write host key\n");
        return Err(());
    }
    let n = syscall_lib::write(fd as i32, &seed);
    close(fd as i32);
    if n != 32 {
        write_str(STDOUT_FILENO, "sshd: short write on host key\n");
        syscall_lib::unlink(HOST_KEY_PATH);
        return Err(());
    }

Key files

  • userspace/sshd/ — Create userspace/sshd/ crate with basic TCP accept loop.

How real OSes differ

  • Production SSH servers (OpenSSH) support SFTP, SCP, port forwarding, tunneling, X11 forwarding, agent forwarding, ProxyJump, certificate auth, and GSSAPI.
  • OpenSSH uses privilege separation (unprivileged child handles the network, privileged parent handles authentication) to limit the impact of vulnerabilities.
  • Real systems support multiple host key types (RSA, ECDSA, Ed25519) and algorithm negotiation across dozens of ciphers and MACs.
  • Dropbear intentionally omits many features for simplicity. Our deployment is further simplified: single-server, no forwarding, no SFTP (initially).
  • Production systems implement connection rate limiting, fail2ban integration, and audit logging for brute-force protection.

Success criteria

  • `sshd` starts at boot and listens on port 22.
  • `ssh user@host` from a standard OpenSSH client connects successfully.
  • Password authentication works.
  • Public key authentication works with `authorized_keys`.
  • The remote shell is fully functional (commands, pipes, editor, compiler).
  • Multiple simultaneous SSH sessions work.
  • Host key fingerprint is stable across reboots.
  • Connection is encrypted (verified by inspecting traffic with tcpdump/wireshark).
  • Closing the SSH client cleanly terminates the remote session.
  • Invalid credentials are rejected.

Related phases

Keep exploring the roadmap