Skip to content

Commit 28ab362

Browse files
committed
read ecdsa public keys to ssh-authorized-keys
Signed-off-by: Ryoka Kujo <[email protected]>
1 parent 9029b1c commit 28ab362

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

pkg/sshutil/sshutil.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package sshutil
22

33
import (
44
"bytes"
5+
"encoding/base64"
6+
"encoding/binary"
57
"errors"
68
"fmt"
79
"io/fs"
@@ -94,7 +96,7 @@ func DefaultPubKeys(loadDotSSH bool) ([]PubKey, error) {
9496
}
9597
entry, err := readPublicKey(f)
9698
if err == nil {
97-
if strings.ContainsRune(entry.Content, '\n') || !strings.HasPrefix(entry.Content, "ssh-") {
99+
if !detectValidPublicKey(entry.Content) {
98100
logrus.Warnf("public key %q doesn't seem to be in ssh format", entry.Filename)
99101
} else {
100102
res = append(res, entry)
@@ -261,3 +263,28 @@ func detectOpenSSHVersion() semver.Version {
261263
}
262264
return v
263265
}
266+
267+
// detectValidPublicKey returns whether content represent a public key.
268+
// OpenSSH public key format have the structure of '<algorithm> <key> <comment>'.
269+
// By checking 'algorithm' with signature format identifier in 'key' part,
270+
// this function may report false positive but provide better compatibility.
271+
func detectValidPublicKey(content string) bool {
272+
if strings.ContainsRune(content, '\n') {
273+
return false
274+
}
275+
var spaced = strings.SplitN(content, " ", 3)
276+
if len(spaced) < 2 {
277+
return false
278+
}
279+
var algo, base64Key = spaced[0], spaced[1]
280+
var decodedKey, err = base64.StdEncoding.DecodeString(base64Key)
281+
if err != nil || len(decodedKey) < 4 {
282+
return false
283+
}
284+
var sigLength = binary.BigEndian.Uint32(decodedKey)
285+
if uint32(len(decodedKey)) < sigLength {
286+
return false
287+
}
288+
var sigFormat = string(decodedKey[4 : 4+sigLength])
289+
return algo == sigFormat
290+
}

pkg/sshutil/sshutil_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,16 @@ func TestParseOpenSSHVersion(t *testing.T) {
2727
// OpenBSD 5.8
2828
assert.Check(t, ParseOpenSSHVersion([]byte("OpenSSH_7.0, LibreSSL")).Equal(*semver.New("7.0.0")))
2929
}
30+
31+
func Test_detectValidPublicKey(t *testing.T) {
32+
assert.Check(t, detectValidPublicKey("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACQDf2IooTVPDBw== 64bit"))
33+
assert.Check(t, detectValidPublicKey("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACQDf2IooTVPDBw=="))
34+
assert.Check(t, detectValidPublicKey("ssh-dss AAAAB3NzaC1kc3MAAACBAP/yAytaYzqXq01uTd5+1RC=" /* truncate */))
35+
assert.Check(t, detectValidPublicKey("ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=" /* truncate */))
36+
assert.Check(t, detectValidPublicKey("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICs1tSO/jx8oc4O=" /* truncate */))
37+
38+
assert.Check(t, !detectValidPublicKey("wrong-algo AAAAB3NzaC1kc3MAAACBAP/yAytaYzqXq01uTd5+1RC="))
39+
assert.Check(t, !detectValidPublicKey("huge-length AAAD6A=="))
40+
assert.Check(t, !detectValidPublicKey("arbitrary content"))
41+
assert.Check(t, !detectValidPublicKey(""))
42+
}

0 commit comments

Comments
 (0)