packer-cn/helper/ssh/key_pair_test.go
Stephen Fox 9592211bcf Honor value of 'Comment' field in 'ssh.KeyPairFromPrivateKey()'.
The 'ssh.KeyPairFromPrivateKey()' function in the 'ssh' helper
library was not honoring the value of the 'Comment' field in the
'FromPrivateKeyConfig' struct. This commit fixes the issue, and
updates unit tests to catch the issue if it happens again.
2019-07-27 15:52:13 -04:00

479 lines
15 KiB
Go

package ssh
import (
"bytes"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"fmt"
"testing"
"github.com/hashicorp/packer/common/uuid"
"golang.org/x/crypto/ed25519"
gossh "golang.org/x/crypto/ssh"
)
const (
pemRsa1024 = `-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDJEMFPpTBiWNDb3qEIPTSeEnIP8FZdBpG8njOrclcMoQQNhzZ+
4uz37tqtHMp36Z7LB4/+85NN6epNXO+ekyZIHswiyBcJC2sT3KuH7nG1BESOooPY
DfeCSM+CJT9GDIhy9nUXSsJjrceEyh/B5DjEtIbS0XfcRelrNTJodCmPJwIDAQAB
AoGAK66GMOV0c4lUJtBhL8cMTWM4gJn4SVGKC+5az16R5t58YOwFPN/UF7E+tOlS
W2bX5sgH0p3cXMr66j/Mlyjk4deLg7trDavulIP93MyVO2SUJ0cstQ0ZmRz2oGwx
Gow+hD75Cet7uvepdmG4DKHJe8D/I72rtP1WKuZyd0vP6WECQQDua6wWlyEdIimx
XoGWUvmywACWPnQmBnyHG7x5hxMjijQoQZu60zRxSU9I5q08BerTsvbTc+xLnDVv
mFzlcjT/AkEA1+P7lcvViZeNKoDB1Qt+VV+pkcqL5aoRwdnLA51SyFJ9tXkxeZwA
LOof3xtoRGhCld7ixi3kF5aZsafAJOZd2QJAH8rFyMFgTgU3MAqdFxF7cGV/7ojn
bgahZlbBfCcR20Rbjh6piHEPZifTZbI02XMkjBQqK6oikTaEPZxAjuv6uwJANczu
yWm+kUdfOpRTuY/fr87jJx3etyEmw7ROz1vJYXqNMUg+eBvUP10pDCR8W2/QCCE/
Sjvtd6NkMc2oKInwIQJAFZ1xJte0EaQsXaCIoZwHrQJbK1dd5l1xTAzz51voAcKH
2K23xgx4I+/eam2enjFa7wXLZFoW0xg/51xsaIjnrA==
-----END RSA PRIVATE KEY-----
`
pemRsa2048 = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA/ZPazeRmBapF01gzHXtJGpu0S936xHY+pOrIyIk6lEE06paf
q5gh6BCuiN/60Keed5Nz+Es4dPGc73mql9pd7N0HOoEc1IQjZzJVqWOy3E55oWbz
rXr1qbmMjw8bGHalZsVBov1UhyB6f2bKi88fGkThJi9HZ+Dc3Jr87eW+whS4D0bI
JJe5dkY0VhDqB0YVEk299TxlAiDkeXD1EcMZrD/yHsusapwlXL2WHWmCgbPpbeYW
YJhD1bScChYmf41iiInBwFymG7kz4bPsup7wCBXpcLJplY1iuXdtVVujNLDbJwlb
Xi2oBm3WizPjYcUthvMlqOieuy6Z4KzyJd7EnQIDAQABAoIBAByZ8LQIbvl0myub
ZyiMH1LA/TURdJd0PtybHsp/r/vI3w8WrivMnQZv2z/VA5VFUrpqB0qaMWP/XJQm
RPebybxNseMHbRkLTnL1WnQgqqvurglmc1W96LecFh6MtaGswDs3RI/9wur63tY/
4dijI/7yhfKoooU097RqRt0ObNW3BxGwNKUraMLKEZjtohv1cZBeRqzGZuui351E
YsG1jt23/3OP3Acfd1xpzoi+daadxl9JTr02kE7lMjfq32quhTdzuNZP84sQsaV+
RXLNEoiSufjzy3nHTEpG6QaEWQc4gszCIBVRabxr7LtIOqJn2KmXxtOyFE52AJJj
ls3ifAECgYEA/9K+5oHdZBizWWUvNzQWXrdHUtVavCwjj+0v+yRFZSoAhKtVmLYl
8R4NeG6NCIOoJsqmGVpgtCyPndR4PQ6yr4Jt1FJorjsNw21eYrjOVG+y9Z0DkCwJ
uCRVUeqB42jLu7v9r1V3OBQdKLN6VxO4np05KEZyv1LOGGt0XC8NCykCgYEA/cC2
NR7Y4Z5OjCc2GHMQNrVZ2HTDDir71RjcIIEmsIQ5/AMAELFLCSqzD73tJ87T5jPi
aWeOpIcnK78jMvIIsbV0BXaDsjtlvCdQui2AoX63FuK4q4E+vwe5Q/TqY2nDh2io
mGHfeXECyUx4gxIede2XEO9zYQ0lP8gxnjmLkFUCgYBO8LolqQcm/xRAzp9eOn14
prekkN+Z10j1/avjpFKhn+9fAPu9zt8wYySm9/4fFXlK1xegFSpoDqQWgNzFgoaS
7/1yGifhM6nQlywb7IkGtx0S+2uBDoXFQ7jsOR/xi4HqoVzrwMS0EkjZKWDkA9rh
XwSnL+3yqduc33OdiotM2QKBgCgNCrVHsSOrQOqOJdOmFaEM7qljhIXv8t+nlNbs
i5bAyAYm0xPPZ/CCdNC/QXdPBdMHzWylk7YUPvKAsKWR3h1ubmmOUysGhQA1lGBO
XkcfIPbTwiIPvD+akHtRZM1cHCh7NGEY0ZTxaWcsUrkdWwFyBq39nVBsKrzudCZt
HsIhAoGBAMv3erZQawzIgX9nOUHB2UJl8pS+LZSNMlYvFoMHKI2hLq0g/VxUlnsh
Jzw9+fTLMVFdY+F3ydO6qQFd8wlfov7deyscdoSj8R5gjGKJsarBs+YVdFde2oLG
gkFsXmbmc2boyqGg51CbAX34VJOhGQKhWgKCWqDGmoYXafmyiZc+
-----END RSA PRIVATE KEY-----
`
pemOpenSshRsa1024 = `-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAIEAzzknaHV741775aJOPacDpd2SiDpIDYmm7/w2sgY8lrinSakfLIVk
1qn0IBRLNOzMxoF/pvIgGQXS51xvE1vB3QK8L+8vJwH06DuOXPP1WgVoDTU03gGvBJ7MNF
5HcQYvBiIaU5XxG8l0OZO88B9RFhPP9r0XrYxAlSjuk9KKlEcAAAIYLQ46zy0OOs8AAAAH
c3NoLXJzYQAAAIEAzzknaHV741775aJOPacDpd2SiDpIDYmm7/w2sgY8lrinSakfLIVk1q
n0IBRLNOzMxoF/pvIgGQXS51xvE1vB3QK8L+8vJwH06DuOXPP1WgVoDTU03gGvBJ7MNF5H
cQYvBiIaU5XxG8l0OZO88B9RFhPP9r0XrYxAlSjuk9KKlEcAAAADAQABAAAAgQDJ9Jq6jF
08P/LhXug/38iHW0UW7S4Ru4jttHGd2MQt5DJtcJzIKA0ZxLL+nKibIPmFsOm2y5yKpolg
IE7EoBVzTeg0LedbRayc0Kc5tY7PEz0Shi9ABIMYbNo2L2pNmsq9ns0xA8ur3OugfKHsH8
XjJ1rdHsyLjoMx2ADfLY0xkQAAAEAvyrgW4jswENdErbF0rOdP+Y73B/8rxBaY/QBE2qtG
oUp7bpOtUAH2Ip7RjXOX4xTAt4n2QeHBSfX7gfXRjmY6AAAAQQDmYlgSWtTYLV9VZSScLU
OG+GkhQxYqkKN/N9LSpTP4Pwh81KpMp40yvIlufmKLgGihWVxUDzRap3aoR7PqIvHPAAAA
QQDmQ47VwclxiVn5tVAht/Lk2ZVa7rSjeFlXAkAWZkUAiHboaH8IfW9W4gYV7o2BqJO11L
0vi+vCq+le45F416wJAAAAImNocmlzQHBvZXRhc3Rlci5jb3JwLm11dHVhbGluay5uZXQ=
-----END OPENSSH PRIVATE KEY-----
`
pemOpenSshRsa2048 = `-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAxWfWNu0i8sbmwPqTUfKSeXOSt/fLMuqucn9KYU7rJ+83trznRhAn
AHQzKgcSU8PBgkax+PDEUexYUB9gZApNI6K/2twVDYh3Hgwx7EjXf05rji7bQk6TFyKEp4
n348CWAdK8iFmNUutSpJLy7GciyMPLu3BK+EsXpsnuPpIm184hEFOiADZyHTGeUgvsKOAc
G7u5hBS3kty8LRZmL+pihbktFwGC4D5bapCcTaF2++zkUy4JKcVE5/2JfK1Ya6D0ATczjz
1b6+r7j2RUg1mXfK6AwMHEcamzhgeuM9RdrPtMdhZI09LCJzjmXc9pzlGu1HCZzh3rJ3hd
8PVmlAd3VQAAA+A9hesQPYXrEAAAAAdzc2gtcnNhAAABAQDFZ9Y27SLyxubA+pNR8pJ5c5
K398sy6q5yf0phTusn7ze2vOdGECcAdDMqBxJTw8GCRrH48MRR7FhQH2BkCk0jor/a3BUN
iHceDDHsSNd/TmuOLttCTpMXIoSniffjwJYB0ryIWY1S61KkkvLsZyLIw8u7cEr4Sxemye
4+kibXziEQU6IANnIdMZ5SC+wo4Bwbu7mEFLeS3LwtFmYv6mKFuS0XAYLgPltqkJxNoXb7
7ORTLgkpxUTn/Yl8rVhroPQBNzOPPVvr6vuPZFSDWZd8roDAwcRxqbOGB64z1F2s+0x2Fk
jT0sInOOZdz2nOUa7UcJnOHesneF3w9WaUB3dVAAAAAwEAAQAAAQEAvA8Z8iWjX6nA9yM/
6ZevluhVY9E60XzlR8qgL2ehet/YMcxwfzywCyyn+WfXO9mHpfZ3YfLs9Ca2U04w4900c7
h+EaAMpmHVKNjxTmpucadhq4hT9S0pz6ZgvcMgVuaHgaEjXroBencYuhQMPM5cQurUUfK+
WSAgnhJNV2qgeoEGgfDZoL1HkItckEZwIzmx4lfMVAuaeqVq5tJNcdv5ukNHpnIYl6fgDp
WGUn/9F8sSHO7P7kGl67IZIsAz+1wW+6pFaVgxbZJ3baPiURtRp+nRSaKLYZSMph6MAiTu
YC8EEVqi3X4m/ZHy+BkphfzR24ouwpt1Vv9QOAPzXXsPwQAAAIEAvmA+yiBdzsJplCifTA
KljE+KpSuvLPRPTb7MGsBO0LIvxrkXOMCXZF4I2VP1zSUH+SDPPc6JeR1Q8liMqPC3Md6c
CIkHfVFBAZL709d0ZtTiir1BipG/l5vIpBnepNX/bWIszIOMzPF2at0WF1lFe6THWujuE8
Xjp2AJSFZlUjAAAACBAOMxr6FN38VwRC1nrDcZyo4TjWVhAdk4p3AkdNJhFSiKS/x5/yo2
K1majzcKbrR8+fEPTVWGszAg+AXQdsOq17q+DMenfrBckQ9ZHr3upSZAaGN+keNwge/Kaj
yOvYiKdYFXmAulQZCPQsDNp7e7Z1dTqxi5IlhUgDPzzO0vRGjNAAAAgQDeb0Ulv7fkYAav
tZ+D0LohGjlGFwTeLdwErcVnq9wGyupdeNhlTXZXxRvF+yEt4FCV9UEUnRX75CAnpk2hT2
D5uYMyixAEfSeIo59Ln27MmAy0alR3UnT7JnLEZRh4dnvFbSSMJ1rHxf8Eg6YFJmpH65fX
exrJE+p69wgRVndoqQAAACJjaHJpc0Bwb2V0YXN0ZXIuY29ycC5tdXR1YWxpbmsubmV0AQ
IDBAUGBw==
-----END OPENSSH PRIVATE KEY-----
`
pemDsa = `-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQDH/T+IkpbdA9nUM7O4MMRoeS0bn7iXWs63Amo2fsIyJPxDvjjF
5HZBH5Rq045TFCCWHjymwiYof+wvwUMZIUH++ABTrKzes/r5qG5jXp42pFWf6nTI
zHwttdjvNiXr+AgreXOrJKhjv6Ga3hq8MNcXMa9xFsIB83EZNMBPxbj0nwIVAJQW
1eR4Uf8/8haQb4HkTsoH+R5/AoGBAK9FV5LIZxY1TeNsD5eXoqpTqCy1WROMggSG
VZ4yN0rrKCtLd8am61m/L8VCMUWiO3IJQdq3yWBTEBbsShL/toau9beUdTl6rdB8
wcEcNgtZnhypQR58HlmgUFWC45rW37hW4AUJuMDgLxgqSVuoF1pDcHrHSi/fZwgp
7t0MKH2SAoGAJfUcLrXg5ZR8jbpZs4L/ubibUn+y35y+33aos07auMW1MesuNTcZ
Ch42nbH2wKnbjk8eDxHdHLHzzOLGgYVMpUuBeuc7G5Q94rM/Z0I8HGQ6mvIkuFyp
58Unu5yu33GsNUgGEHmriiMGezXNXGNH/72PmTXuyxEMSrad23c6NZoCFAtIqbal
4tGCfnnmWU514A7ZzEKj
-----END DSA PRIVATE KEY-----
`
pemEcdsa384 = `-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAjuEIlmFyhGjFtJoAwD420FuPAjIknN3YwDZL4cfMFpB4YAK+7QVLs
coAJ/ADuT7OgBwYFK4EEACKhZANiAASeXKyBr2prr4f4aOsM4dtVikYOUIL3yYnb
GFOy7yHmauCnkIB48paXpvRE5m53Q8zgu7vkz/z9tcMBcC0GzpY3Sef37fmgTUuZ
AJuJp36DMBdQel+j51TcQ79sizxCayg=
-----END EC PRIVATE KEY-----
`
pemEcdsa521 = `-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBVCiwcf/did2vCIu3aMe7OeTD35PULm0hqmfkAK9OKIosi/DjOFfA
8h99rVNPaf+Cx/JNmEzR4bZNnYDyilSRCr+gBwYFK4EEACOhgYkDgYYABABHBMLP
XbQoRF31ZGIeUj9jt9GqKES1dLBtGDEQSiiZFouL4tEIW7NfIZDpOIkA0khNcO8N
xH6eylg0XOgcr01GRwCjY5VOapOahtn63SpajPGeKk+46F2dULIwrov9tWQuYNa3
P50N8j3rx6fAdgyDENOcCJlfNdNcySvkH4bgL1xcsw==
-----END EC PRIVATE KEY-----
`
pemOpenSshEd25519 = `-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAUftPhZQN17kAlThiiWJEgJvddm/pUhHvgrHUtpuYFOQAAAKjN+UhDzflI
QwAAAAtzc2gtZWQyNTUxOQAAACAUftPhZQN17kAlThiiWJEgJvddm/pUhHvgrHUtpuYFOQ
AAAEANXlEZdNU03RMmj77O2ojWh06Hbj8/qQ++H5wkt688NBR+0+FlA3XuQCVOGKJYkSAm
912b+lSEe+CsdS2m5gU5AAAAImNocmlzQHBvZXRhc3Rlci5jb3JwLm11dHVhbGluay5uZX
QBAgM=
-----END OPENSSH PRIVATE KEY-----
`
)
func TestNewKeyPair_Default(t *testing.T) {
kp, err := NewKeyPair(CreateKeyPairConfig{})
if err != nil {
t.Fatal(err.Error())
}
err = verifyEcdsaKeyPair(kp, expectedData{
bits: 521,
})
if err != nil {
t.Fatal(err.Error())
}
}
func TestNewKeyPair_ECDSA_Default(t *testing.T) {
kp, err := NewKeyPair(CreateKeyPairConfig{
Type: Ecdsa,
})
if err != nil {
t.Fatal(err.Error())
}
err = verifyEcdsaKeyPair(kp, expectedData{
bits: 521,
})
if err != nil {
t.Fatal(err.Error())
}
}
func TestNewKeyPair_ECDSA_Positive(t *testing.T) {
for _, bits := range []int{521, 384, 256} {
config := CreateKeyPairConfig{
Type: Ecdsa,
Bits: bits,
Comment: uuid.TimeOrderedUUID(),
}
kp, err := NewKeyPair(config)
if err != nil {
t.Fatal(err.Error())
}
err = verifyEcdsaKeyPair(kp, expectedData{
bits: bits,
comment: config.Comment,
})
if err != nil {
t.Fatal(err.Error())
}
}
}
func TestNewKeyPair_ECDSA_Negative(t *testing.T) {
for _, bits := range []int{224, 1, 2, 3} {
_, err := NewKeyPair(CreateKeyPairConfig{
Type: Ecdsa,
Bits: bits,
})
if err == nil {
t.Fatalf("expected key pair generation to fail for %d bits", bits)
}
}
}
func TestNewKeyPair_RSA_Positive(t *testing.T) {
for _, bits := range []int{4096, 2048} {
config := CreateKeyPairConfig{
Type: Rsa,
Bits: bits,
Comment: uuid.TimeOrderedUUID(),
}
kp, err := NewKeyPair(config)
if err != nil {
t.Fatal(err.Error())
}
err = verifyRsaKeyPair(kp, expectedData{
bits: config.Bits,
comment: config.Comment,
})
if err != nil {
t.Fatal(err.Error())
}
}
}
func TestKeyPairFromPrivateKey(t *testing.T) {
m := map[string]fromPrivateExpectedData{
pemRsa1024: {
t: Rsa,
d: expectedData{
bits: 1024,
comment: uuid.TimeOrderedUUID(),
},
},
pemRsa2048: {
t: Rsa,
d: expectedData{
bits: 2048,
comment: uuid.TimeOrderedUUID(),
},
},
pemOpenSshRsa1024: {
t: Rsa,
d: expectedData{
bits: 1024,
comment: uuid.TimeOrderedUUID(),
},
},
pemOpenSshRsa2048: {
t: Rsa,
d: expectedData{
bits: 2048,
comment: uuid.TimeOrderedUUID(),
},
},
pemDsa: {
t: Dsa,
d: expectedData{
bits: 1024,
comment: uuid.TimeOrderedUUID(),
},
},
pemEcdsa384: {
t: Ecdsa,
d: expectedData{
bits: 384,
comment: uuid.TimeOrderedUUID(),
},
},
pemEcdsa521: {
t: Ecdsa,
d: expectedData{
bits: 521,
comment: uuid.TimeOrderedUUID(),
},
},
pemOpenSshEd25519: {
t: Ed25519,
d: expectedData{
bits: 256,
comment: uuid.TimeOrderedUUID(),
},
},
}
for rawPrivateKey, expected := range m {
kp, err := KeyPairFromPrivateKey(FromPrivateKeyConfig{
RawPrivateKeyPemBlock: []byte(rawPrivateKey),
Comment: expected.d.comment,
})
if err != nil {
t.Fatal(err.Error())
}
switch expected.t {
case Dsa:
err = verifyDsaKeyPair(kp, expected)
case Ecdsa:
err = verifyEcdsaKeyPair(kp, expected.d)
case Ed25519:
err = verifyEd25519KeyPair(kp, expected)
case Rsa:
err = verifyRsaKeyPair(kp, expected.d)
default:
err = fmt.Errorf("unexected SSH key pair type %s", expected.t.String())
}
if err != nil {
t.Fatal(err.Error())
}
}
}
type fromPrivateExpectedData struct {
t KeyPairType
d expectedData
}
type expectedData struct {
bits int
comment string
}
func verifyEcdsaKeyPair(kp KeyPair, e expectedData) error {
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
if err != nil {
return err
}
pk, ok := privateKey.(*ecdsa.PrivateKey)
if !ok {
return fmt.Errorf("private key should be *ecdsa.PrivateKey")
}
if pk.Curve.Params().BitSize != e.bits {
return fmt.Errorf("bit size should be %d - got %d", e.bits, pk.Curve.Params().BitSize)
}
publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
if err != nil {
return err
}
if kp.Comment != e.comment {
return fmt.Errorf("key pair comment should be:\n'%s'\nGot:\n'%s'",
e.comment, kp.Comment)
}
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
if len(e.comment) > 0 {
expectedBytes = append(expectedBytes, ' ')
expectedBytes = append(expectedBytes, e.comment...)
}
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
}
return nil
}
func verifyRsaKeyPair(kp KeyPair, e expectedData) error {
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
if err != nil {
return err
}
pk, ok := privateKey.(*rsa.PrivateKey)
if !ok {
return fmt.Errorf("private key should be *rsa.PrivateKey")
}
if pk.N.BitLen() != e.bits {
return fmt.Errorf("bit size should be %d - got %d", e.bits, pk.N.BitLen())
}
publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
if err != nil {
return err
}
if kp.Comment != e.comment {
return fmt.Errorf("key pair comment should be:\n'%s'\nGot:\n'%s'",
e.comment, kp.Comment)
}
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
if len(e.comment) > 0 {
expectedBytes = append(expectedBytes, ' ')
expectedBytes = append(expectedBytes, e.comment...)
}
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
}
return nil
}
func verifyDsaKeyPair(kp KeyPair, e fromPrivateExpectedData) error {
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
if err != nil {
return err
}
pk, ok := privateKey.(*dsa.PrivateKey)
if !ok {
return fmt.Errorf("private key should be *rsa.PrivateKey")
}
publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
if err != nil {
return err
}
if kp.Comment != e.d.comment {
return fmt.Errorf("key pair comment should be:\n'%s'\nGot:\n'%s'",
e.d.comment, kp.Comment)
}
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
if len(e.d.comment) > 0 {
expectedBytes = append(expectedBytes, ' ')
expectedBytes = append(expectedBytes, e.d.comment...)
}
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
}
return nil
}
func verifyEd25519KeyPair(kp KeyPair, e fromPrivateExpectedData) error {
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
if err != nil {
return err
}
pk, ok := privateKey.(*ed25519.PrivateKey)
if !ok {
return fmt.Errorf("private key should be *rsa.PrivateKey")
}
publicKey, err := gossh.NewPublicKey(pk.Public())
if err != nil {
return err
}
if kp.Comment != e.d.comment {
return fmt.Errorf("key pair comment should be:\n'%s'\nGot:\n'%s'",
e.d.comment, kp.Comment)
}
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
if len(e.d.comment) > 0 {
expectedBytes = append(expectedBytes, ' ')
expectedBytes = append(expectedBytes, e.d.comment...)
}
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
}
return nil
}