Skip to content

Commit 4c7d1bb

Browse files
author
Santhanam
committed
ssh: fix error message on unsupported cipher
Fixes golang/go#52135 Until now, when ssh keys using one of these[1] ciphers were passed, we were giving a parse error "ssh: parse error in message type 0". With this fix, we parse it successfully and return the correct error message. [1] aes{128,256}[email protected] and [email protected]
1 parent 2beaa59 commit 4c7d1bb

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

ssh/keys.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,15 @@ func (*PassphraseMissingError) Error() string {
12711271
return "ssh: this private key is passphrase protected"
12721272
}
12731273

1274+
type UnsupportedCipherError struct {
1275+
BadCipher string
1276+
SupportedCiphers []string
1277+
}
1278+
1279+
func (e *UnsupportedCipherError) Error() string {
1280+
return fmt.Sprintf("ssh: unknown cipher %q, only supports one of %q", e.BadCipher, strings.Join(e.SupportedCiphers, ","))
1281+
}
1282+
12741283
// ParseRawPrivateKey returns a private key from a PEM encoded private key. It supports
12751284
// RSA, DSA, ECDSA, and Ed25519 private keys in PKCS#1, PKCS#8, OpenSSL, and OpenSSH
12761285
// formats. If the private key is encrypted, it will return a PassphraseMissingError.
@@ -1429,7 +1438,10 @@ func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
14291438
cbc := cipher.NewCBCDecrypter(c, iv)
14301439
cbc.CryptBlocks(privKeyBlock, privKeyBlock)
14311440
default:
1432-
return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc")
1441+
return nil, &UnsupportedCipherError{
1442+
BadCipher: cipherName,
1443+
SupportedCiphers: []string{"aes256-ctr", "aes256-cbc"},
1444+
}
14331445
}
14341446

14351447
return privKeyBlock, nil
@@ -1490,6 +1502,7 @@ type openSSHEncryptedPrivateKey struct {
14901502
NumKeys uint32
14911503
PubKey []byte
14921504
PrivKeyBlock []byte
1505+
Rest []byte `ssh:"rest"`
14931506
}
14941507

14951508
type openSSHPrivateKey struct {

ssh/keys_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@ func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) {
271271
}
272272
}
273273

274+
func TestParseEncryptedPrivateKeysWithUnsupportedCiphers(t *testing.T) {
275+
for _, tt := range testdata.PEMEncryptedKeysForUnsupportedCiphers {
276+
t.Run(tt.Name, func(t *testing.T) {
277+
_, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte(tt.EncryptionKey))
278+
var e *UnsupportedCipherError
279+
if !errors.As(err, &e) {
280+
t.Errorf("got error %v, want PassphraseMissingError", err)
281+
}
282+
283+
if e.BadCipher != tt.Cipher {
284+
t.Errorf("got badcipher %q, wanted %q", e.BadCipher, tt.Cipher)
285+
}
286+
})
287+
}
288+
}
289+
274290
func TestParseEncryptedPrivateKeysWithIncorrectPassphrase(t *testing.T) {
275291
pem := testdata.PEMEncryptedKeys[0].PEMBytes
276292
for i := 0; i < 4096; i++ {

ssh/testdata/keys.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,15 @@ var SSHCertificates = map[string][]byte{
216216
`),
217217
}
218218

219-
var PEMEncryptedKeys = []struct {
219+
type PEMEncryptedKey struct {
220220
Name string
221221
EncryptionKey string
222222
IncludesPublicKey bool
223+
Cipher string
223224
PEMBytes []byte
224-
}{
225+
}
226+
227+
var PEMEncryptedKeys = []PEMEncryptedKey{
225228
0: {
226229
Name: "rsa-encrypted",
227230
EncryptionKey: "r54-G0pher_t3st$",
@@ -310,6 +313,54 @@ gbDGyT3bXMQtagvCwoW+/oMTKXiZP5jCJpEO8=
310313
},
311314
}
312315

316+
var PEMEncryptedKeysForUnsupportedCiphers = []PEMEncryptedKey{
317+
0: {
318+
Name: "ed25519-encrypted-chacha20-poly1305",
319+
EncryptionKey: "password",
320+
IncludesPublicKey: true,
321+
Cipher: "[email protected]",
322+
PEMBytes: []byte(`-----BEGIN OPENSSH PRIVATE KEY-----
323+
b3BlbnNzaC1rZXktdjEAAAAAHWNoYWNoYTIwLXBvbHkxMzA1QG9wZW5zc2guY29tAAAABm
324+
JjcnlwdAAAABgAAAAQdPyPIjXDRAVHskY0yp9SWwAAAGQAAAABAAAAMwAAAAtzc2gtZWQy
325+
NTUxOQAAACBi6qXITEUrmNce/c2lfozxALlKH3o/6sll8G7wzl1lvQAAAJDNlW1sEkvnK0
326+
8EecF1vHdPk85yClbh3KkHv09mbGAX/Gk6cJpYEGgJSkO7OEF4kG9DVGGd17+TZbTnM4LD
327+
vYAJZExx2XLgJFEtHCVmJjYzwxx7yC7+s6u/XjrSlZS60RHunOPKyq+C+s48sejXvmX+t5
328+
0ZoVCI8aftT0ycis3gvLU9sCwJ2UnF6kAV226Z4g2aLkuJbgCDTEcYCRD64K1r
329+
-----END OPENSSH PRIVATE KEY-----
330+
`),
331+
},
332+
1: {
333+
Name: "ed25519-encrypted-aes128-gcm",
334+
EncryptionKey: "password",
335+
IncludesPublicKey: true,
336+
Cipher: "[email protected]",
337+
PEMBytes: []byte(`-----BEGIN OPENSSH PRIVATE KEY-----
338+
b3BlbnNzaC1rZXktdjEAAAAAFmFlczEyOC1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA
339+
AAGAAAABBeMJIOqiyFwNCvDv6f8tQeAAAAZAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAA
340+
IGYpUcb3tGp9kF6pppcUdq3EPMr85BaSUdhiXGbhS5YNAAAAkNBtMEu0UlLgToThuQc+4m
341+
/o0DfFIERu0sspQivn5RJHCtulVKfU9BMiEnF0+LOMOABMlYesgLOtoMxwm4ZCSWH54kZk
342+
vaFyyvvxY+RLDuWNQZCryffIA4+iLCUQR1EdxMDiJweKnGJuD64a+9xTJt47A3Vq4SYzji
343+
EuVmM0FqS8lbT2ynYSe3va0Qyw13jEO5qbtCuyG+C5GejL7kX4Z64=
344+
-----END OPENSSH PRIVATE KEY-----
345+
`),
346+
},
347+
2: {
348+
Name: "ed25519-encrypted-aes256-gcm",
349+
EncryptionKey: "password",
350+
IncludesPublicKey: true,
351+
Cipher: "[email protected]",
352+
PEMBytes: []byte(`-----BEGIN OPENSSH PRIVATE KEY-----
353+
b3BlbnNzaC1rZXktdjEAAAAAFmFlczI1Ni1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA
354+
AAGAAAABBR1p3vH2Wr/HPL+q20L2rjAAAAZAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAA
355+
IM3tT1xrAuOHcrBdoLRo/ojWZsAw2lHfF5hJgFEOts5MAAAAkH/YGrDhDw8u+F8e4P+84B
356+
tAzvp55Lf1Yl7y34BrVmqlWqw/7boqahOp6iYJHNpcuanzc5T6s7Z3wSSYodbY1uvFOfbj
357+
rtP6rIHQIY5J2C40WOYJN8IkZlkwDXwZY0qoE9699ZYmWdwsXRZ7QDhjd2W8ziyZBsttiB
358+
kv2ceuJMLT04TrKc2+RUkj4CQYnz7p8EkgZlUozx8wBSxKFGnkP7k=
359+
-----END OPENSSH PRIVATE KEY-----
360+
`),
361+
},
362+
}
363+
313364
// SKData contains a list of PubKeys backed by U2F/FIDO2 Security Keys and their test data.
314365
var SKData = []struct {
315366
Name string

0 commit comments

Comments
 (0)