SSH services using TOFU are proliferating, particularly for user onboarding and payment processing. The TOFU model is vulnerable to man-in-the-middle attacks on first connection, which is especially problematic in easy to arrange hostile network environments like conference WiFi or coffee shops.
While SSH supports SSHFP DNS records for host key verification, this mechanism is:
- Disabled by default in most SSH clients
- Vulnerable to DNS spoofing unless DNSSEC is used
- Not widely deployed
The risk is concrete, an example: A user at a conference connects to a new SSH service through a compromised network. The attacker intercepts the connection, presents their own host key, and the user accepts it. The user uses the service normally, involving either making a purchase or using credentials to upstream services. The attacker makes use of the intercepted payment details, uses the intercepted credentials or installs persistent backdoors.
Add a standardized HTTPS endpoint at /.well-known/ssh_known_hosts that serves the SSH
host keys for a domain. SSH clients would attempt to fetch this file via HTTPS with
standard WebPKI validation before accepting a new host key.
When connecting to a host with no existing known_hosts entry:
- Attempt HTTPS connection to
https://[hostname]/.well-known/ssh_known_hosts - Validate TLS certificate using system WebPKI trust store
- Parse returned file as standard SSH known_hosts format
- Only trust entries matching the target hostname, discard others
- Compare SSH host key from connection against entries in file
- If mismatch or fetch failure, inform user and proceed with standard TOFU
This should be enabled by default for hosts with unknown keys with graceful fallback to standard TOFU behavior.
Standard SSH known_hosts format:
example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...
Optional extensions for key rotation:
# Valid-After: 2025-12-15T00:00:00Z
# Valid-Before: 2026-12-15T00:00:00Z
example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
- Serve file over HTTPS with valid TLS certificate
- Include only host keys for the serving domain
- Set appropriate cache headers (suggested: 24 hour max-age)
- Update file when host keys are rotated
This mechanism:
- Prevents casual MITM attacks in hostile network environments
- Leverages existing WebPKI infrastructure
- Maintains backward compatibility through graceful degradation
- Does not require DNS modifications or DNSSEC deployment
This mechanism does not prevent:
- Attacks by actors with CA compromise or compelled certificate issuance
- Attacks after initial trust establishment (standard SSH threat model)
- DNS-based attacks (domain hijacking affects both SSH and HTTPS)
The trust model shifts from pure TOFU to WebPKI-anchored first connection. This is a meaningful improvement for the common case of conference or public WiFi attacks.
Clients should:
- Use short timeouts (5 seconds) for HTTPS requests
- Follow redirects (maximum 3)
- Cache retrieved keys with TTL matching HTTP cache headers
- Log all fetch attempts for debugging
- Make this behavior configurable but default-enabled
Suggest new configuration option:
StrictHostKeyChecking well-known
This would enable the behavior described above. Eventually this could become the default
behavior for StrictHostKeyChecking ask.
- Publish specification
- Implement in SSH client libraries (Go, Rust, Python)
- Deploy endpoints for major SSH services
- Propose patch to OpenSSH upstream
- Advocate for default-enabled behavior after proving value
Services that would benefit:
- Developer platforms with SSH-based onboarding
- Payment services using SSH as transport
- Git hosting providers
- Remote development environments
- SSH-based credential management systems
Perhaps configurable? It's up to the user if they want to fully trust WebPKI.
Perhaps a preference order could be configured, but it seems that WebPKI is better deployed than DNSSEC at this time and the forseeable future. If there's a discrepancy the client should almost certainly warn the user.
Great steps, crawshaw independently decided to do almost the exact same thing and now owns it under c2sp (which I'd forgotten about): C2SP/C2SP#188