using System.Text; using DodoSSH.Client.Ssh; namespace DodoSSH.Client.Session; /// /// The throwaway key one connection signs in to a Spelunk server with. /// /// /// /// For a host set to sign in through Spelunk — see SpelunkRoute.SignInThroughSpelunk — each connection /// makes one of these, sends with its ticket request, and authenticates with /// once the tunnel is up. Spelunk's agent runs a one-connection SSH server whose only /// authorised key is this one, so the key is worth nothing after the connection it was made for. /// /// /// Made in memory and never kept. Nothing writes it to a disk or to the vault, and nothing logs it: /// says what it is and nothing of what it holds. Ed25519, which is what /// makes instantly and what every OpenSSH the agent could start accepts. /// /// public sealed class SpelunkSignIn { /// The account Spelunk signs in as when its answer does not name one. public const string DefaultUser = "root"; /// The comment the public key carries, which is what Spelunk and the server's logs see. internal const string KeyComment = "dodossh-spelunk-sign-in"; private SpelunkSignIn(string publicKeyLine, SshPrivateKeyCredential credential) { PublicKeyLine = publicKeyLine; Credential = credential; } /// The public half, as one OpenSSH authorized_keys line: ssh-ed25519 AAAA… comment. public string PublicKeyLine { get; } /// The private half, in the form a connection authenticates with. public SshPrivateKeyCredential Credential { get; } /// Makes a fresh key pair for one connection. public static SpelunkSignIn Create() { var key = SshKeyGenerator.Generate(SshKeyAlgorithm.Ed25519, KeyComment); return new SpelunkSignIn( key.PublicKeyLine.Trim(), new SshPrivateKeyCredential(Encoding.UTF8.GetBytes(key.PrivateKeyArmour), Passphrase: null)); } /// /// Says nothing of the key, so one that reaches a log by accident takes nothing with it. public override string ToString() => "Spelunk sign-in key"; } /// /// The credential of a connection that will sign in through Spelunk, before the tunnel has made its key. /// /// /// /// A host that signs in through Spelunk is resolved to a login before anything is opened — the same /// resolution every host goes through — but its key does not exist until the tunnel is opened, and the /// account is whatever Spelunk then says. This stands in for the key until the route replaces it, together /// with the username, as the connection is made through it. /// /// /// It authenticates nothing. The SSH layer knows only passwords and private keys, and refuses any other /// credential before it dials — so a path that forgot to take the route's key fails closed rather than /// sending something else in its place. /// /// public sealed record SpelunkSignInPending : SshCredential { /// The one value; there is nothing in it to tell two apart. public static SpelunkSignInPending Instance { get; } = new(); private SpelunkSignInPending() { } }