internal/server/api/injectedkey.go
Ref: Size: 2.6 KiB History
package api
import (
"strings"
"github.com/a73x/eitri/internal/server/api/types"
"github.com/a73x/eitri/internal/server/store"
"golang.org/x/crypto/ssh"
)
// maxKeyCommentLen bounds the comment kept from a user-supplied key. It is
// free text that ends up rendered in the console, and an authorized_keys
// comment is conventionally a short "user@host" — anything longer is either a
// mistake or an attempt to fill a column.
const maxKeyCommentLen = 128
// describeKey summarises the authorized key eitri is about to install, for the
// record kept on the VM row. It returns the key type, its SHA256 fingerprint in
// OpenSSH's own spelling, and the key's comment.
//
// It DESCRIBES rather than validates. Create deliberately accepts any
// single-line key — the guest's sshd is the thing that decides what it will
// honour, and refusing a key here on cryptographic grounds would be eitri
// second-guessing it. So a key that cannot be parsed still yields whatever can
// be said about it: the leading token as its type, and no fingerprint. An empty
// fingerprint is the signal that the key was unreadable, not that none exists.
//
// A key eitri never installed returns three empty strings, which is a different
// statement entirely: nothing was injected.
func describeKey(line string) (keyType, fingerprint, comment string) {
line = strings.TrimSpace(line)
if line == "" {
return "", "", ""
}
pub, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(line))
if err != nil {
// Unreadable: say what it claims to be and nothing more. The first
// field of an authorized_keys line is its type by convention, and a
// claim is still worth showing next to "we could not read this".
return firstField(line), "", ""
}
if len(comment) > maxKeyCommentLen {
comment = comment[:maxKeyCommentLen]
}
return pub.Type(), ssh.FingerprintSHA256(pub), comment
}
// firstField returns the first whitespace-separated token of s, bounded so an
// unparseable line cannot contribute an unbounded "type".
func firstField(s string) string {
if i := strings.IndexAny(s, " \t"); i >= 0 {
s = s[:i]
}
if len(s) > 32 {
s = s[:32]
}
return s
}
// injectedKey renders a VM row's recorded key for the wire, or nil when eitri
// installed none. It is derived and read-only: the key itself stays write-only,
// like every other field a create accepts and no response echoes.
func injectedKey(vm store.VM) *types.InjectedKey {
if vm.InjectedKeyType == "" && vm.InjectedKeyFP == "" {
return nil
}
return &types.InjectedKey{
Type: vm.InjectedKeyType,
Fingerprint: vm.InjectedKeyFP,
Comment: vm.InjectedKeyComment,
}
}