[remark] SSH authorization keys experiments

by Ciprian Dorin Craciun (https://volution.ro/ciprian) on 

Experimenting with OpenSSH authorization keys resolution; from skeleton-key providing emergency access, to simple centralized key management.

// permanent-link // Lobsters // HackerNews // index // RSS

Last week, while brainstorming with a colleague, I discovered a few interesting options with regard to OpenSSH public key authentication mechanisms, specifically how OpenSSH resolves which public keys are allowed for a particular user.

First of all, we all know the ~/.ssh/authorized_keys file, but there is more. According to the sshd_config(5) manual page, we can control this resolution process through the following options:

Here are a few interesting use-cases for these options:

!!!WARNING!!! -- when querying external sources, especially without additional authentication or encryption, care must be taken so that an attacker can't use this feature to explore and discover your internal infrastructure, or determine which employees have access to high-value targets.

For experimentation purposes, I've tried to implement a small proof-of-concept that verifies if a particular SSH public key, for a particular host and user, is allowed to authenticate, while taking into account the warning above about discovery attacks.

Although the code is not (yet) open-source, here are a few guide-lines based on its implementation:

The following are the security properties of the whole system:

Care must be taken when computing the two bucket tokens, especially with regard to canonicalization attacks, for example I've used the following construct:

let secret_hash = blake3_derive_key (context = "ssh-ack v1 / secret", data = secret_string)
let context_data = join_strings (infix = "\0", strings = ["ssh-ack v1", host, user, ssh_key_type, ssh_key_data])
let context_hash = blake3_keyed_hash (key = secret_hash, data = context_data)
let bucket_key = blake3_derive_key (context = "ssh-ack v1 / bucket key", data = context_hash) .encode_to_hex
let bucket_data = blake3_derive_key (context = "ssh-ack v1 / bucket data", data = context_hash) .encode_to_hex

!!!WARNING!!! -- needless to say, I'm not a cryptographer, and I didn't do a thorough security analysis of this proposed scheme. Thus, use your common sense!