blob: 334ef7453266db369811c6494c2924f9732e18bc [file] [log] [blame]
Adam Langleyfa50e742014-04-09 13:57:52 -07001// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -04005package ssh
6
7import (
Adam Langleyfa50e742014-04-09 13:57:52 -07008 "bytes"
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -04009 "crypto/dsa"
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040010 "crypto/ecdsa"
11 "crypto/elliptic"
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040012 "crypto/rand"
13 "crypto/rsa"
Yasuhiro Matsumoto84f24df2017-06-23 19:03:27 +090014 "crypto/x509"
Adam Langleyfa50e742014-04-09 13:57:52 -070015 "encoding/base64"
Sebastian Kinne86a70502019-11-19 16:30:15 -080016 "encoding/hex"
Adam Langley0709b302018-08-31 15:38:59 -070017 "encoding/pem"
Adam Langleyfa50e742014-04-09 13:57:52 -070018 "fmt"
Adam Langley0709b302018-08-31 15:38:59 -070019 "io"
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040020 "reflect"
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040021 "strings"
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040022 "testing"
Adam Langleyfa50e742014-04-09 13:57:52 -070023
Martin Garton1e61df82016-04-30 22:10:58 +010024 "golang.org/x/crypto/ed25519"
Andrew Gerranda73c6bb2014-11-10 08:50:25 +110025 "golang.org/x/crypto/ssh/testdata"
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040026)
27
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040028func rawKey(pub PublicKey) interface{} {
29 switch k := pub.(type) {
30 case *rsaPublicKey:
31 return (*rsa.PublicKey)(k)
32 case *dsaPublicKey:
33 return (*dsa.PublicKey)(k)
34 case *ecdsaPublicKey:
35 return (*ecdsa.PublicKey)(k)
Martin Garton1e61df82016-04-30 22:10:58 +010036 case ed25519PublicKey:
37 return (ed25519.PublicKey)(k)
Adam Langleyfa50e742014-04-09 13:57:52 -070038 case *Certificate:
Jonathan Pittman9112f502013-10-22 15:12:41 -040039 return k
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040040 }
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040041 panic("unknown key type")
42}
43
44func TestKeyMarshalParse(t *testing.T) {
Adam Langleyfa50e742014-04-09 13:57:52 -070045 for _, priv := range testSigners {
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040046 pub := priv.PublicKey()
Adam Langleyfa50e742014-04-09 13:57:52 -070047 roundtrip, err := ParsePublicKey(pub.Marshal())
48 if err != nil {
49 t.Errorf("ParsePublicKey(%T): %v", pub, err)
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040050 }
51
52 k1 := rawKey(pub)
53 k2 := rawKey(roundtrip)
54
55 if !reflect.DeepEqual(k1, k2) {
56 t.Errorf("got %#v in roundtrip, want %#v", k2, k1)
57 }
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040058 }
59}
60
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040061func TestUnsupportedCurves(t *testing.T) {
62 raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040063 if err != nil {
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040064 t.Fatalf("GenerateKey: %v", err)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040065 }
66
Evan Brodere74b0352015-06-12 19:11:01 +020067 if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P-256") {
68 t.Fatalf("NewPrivateKey should not succeed with P-224, got: %v", err)
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040069 }
70
Evan Brodere74b0352015-06-12 19:11:01 +020071 if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P-256") {
72 t.Fatalf("NewPublicKey should not succeed with P-224, got: %v", err)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -040073 }
74}
75
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040076func TestNewPublicKey(t *testing.T) {
Adam Langleyfa50e742014-04-09 13:57:52 -070077 for _, k := range testSigners {
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040078 raw := rawKey(k.PublicKey())
Adam Langleyfa50e742014-04-09 13:57:52 -070079 // Skip certificates, as NewPublicKey does not support them.
80 if _, ok := raw.(*Certificate); ok {
81 continue
82 }
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040083 pub, err := NewPublicKey(raw)
84 if err != nil {
85 t.Errorf("NewPublicKey(%#v): %v", raw, err)
86 }
87 if !reflect.DeepEqual(k.PublicKey(), pub) {
88 t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey())
89 }
90 }
91}
92
93func TestKeySignVerify(t *testing.T) {
Adam Langleyfa50e742014-04-09 13:57:52 -070094 for _, priv := range testSigners {
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040095 pub := priv.PublicKey()
96
97 data := []byte("sign me")
98 sig, err := priv.Sign(rand.Reader, data)
99 if err != nil {
100 t.Fatalf("Sign(%T): %v", priv, err)
101 }
102
Adam Langleyfa50e742014-04-09 13:57:52 -0700103 if err := pub.Verify(data, sig); err != nil {
104 t.Errorf("publicKey.Verify(%T): %v", priv, err)
105 }
106 sig.Blob[5]++
107 if err := pub.Verify(data, sig); err == nil {
108 t.Errorf("publicKey.Verify on broken sig did not fail")
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400109 }
110 }
111}
112
Ian Hakendab2b102018-10-29 02:07:14 +0000113func TestKeySignWithAlgorithmVerify(t *testing.T) {
114 for _, priv := range testSigners {
115 if algorithmSigner, ok := priv.(AlgorithmSigner); !ok {
116 t.Errorf("Signers constructed by ssh package should always implement the AlgorithmSigner interface: %T", priv)
117 } else {
118 pub := priv.PublicKey()
119 data := []byte("sign me")
120
121 signWithAlgTestCase := func(algorithm string, expectedAlg string) {
122 sig, err := algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm)
123 if err != nil {
124 t.Fatalf("Sign(%T): %v", priv, err)
125 }
126 if sig.Format != expectedAlg {
127 t.Errorf("signature format did not match requested signature algorithm: %s != %s", sig.Format, expectedAlg)
128 }
129
130 if err := pub.Verify(data, sig); err != nil {
131 t.Errorf("publicKey.Verify(%T): %v", priv, err)
132 }
133 sig.Blob[5]++
134 if err := pub.Verify(data, sig); err == nil {
135 t.Errorf("publicKey.Verify on broken sig did not fail")
136 }
137 }
138
139 // Using the empty string as the algorithm name should result in the same signature format as the algorithm-free Sign method.
140 defaultSig, err := priv.Sign(rand.Reader, data)
141 if err != nil {
142 t.Fatalf("Sign(%T): %v", priv, err)
143 }
144 signWithAlgTestCase("", defaultSig.Format)
145
146 // RSA keys are the only ones which currently support more than one signing algorithm
147 if pub.Type() == KeyAlgoRSA {
Filippo Valsordafcc990c2022-03-14 06:24:16 -0400148 for _, algorithm := range []string{KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512} {
Ian Hakendab2b102018-10-29 02:07:14 +0000149 signWithAlgTestCase(algorithm, algorithm)
150 }
151 }
152 }
153 }
154}
155
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400156func TestParseRSAPrivateKey(t *testing.T) {
Adam Langleyfa50e742014-04-09 13:57:52 -0700157 key := testPrivateKeys["rsa"]
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400158
Adam Langleyfa50e742014-04-09 13:57:52 -0700159 rsa, ok := key.(*rsa.PrivateKey)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400160 if !ok {
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400161 t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400162 }
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400163
164 if err := rsa.Validate(); err != nil {
165 t.Errorf("Validate: %v", err)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400166 }
167}
168
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400169func TestParseECPrivateKey(t *testing.T) {
Adam Langleyfa50e742014-04-09 13:57:52 -0700170 key := testPrivateKeys["ecdsa"]
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400171
Adam Langleyfa50e742014-04-09 13:57:52 -0700172 ecKey, ok := key.(*ecdsa.PrivateKey)
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400173 if !ok {
Adam Langleyfa50e742014-04-09 13:57:52 -0700174 t.Fatalf("got %T, want *ecdsa.PrivateKey", ecKey)
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -0400175 }
176
177 if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
178 t.Fatalf("public key does not validate.")
179 }
180}
181
Yasuhiro Matsumotofea6c2c2017-02-02 15:10:04 +0900182func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) {
183 data := []byte("sign me")
184 for _, tt := range testdata.PEMEncryptedKeys {
Filippo Valsorda0a08dad2019-11-17 18:43:54 -0500185 t.Run(tt.Name, func(t *testing.T) {
186 _, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte("incorrect"))
187 if err != x509.IncorrectPasswordError {
188 t.Errorf("got %v want IncorrectPasswordError", err)
189 }
Yasuhiro Matsumoto84f24df2017-06-23 19:03:27 +0900190
Filippo Valsorda0a08dad2019-11-17 18:43:54 -0500191 s, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte(tt.EncryptionKey))
192 if err != nil {
193 t.Fatalf("ParsePrivateKeyWithPassphrase returned error: %s", err)
194 }
195
196 sig, err := s.Sign(rand.Reader, data)
197 if err != nil {
198 t.Fatalf("Signer.Sign: %v", err)
199 }
200 if err := s.PublicKey().Verify(data, sig); err != nil {
201 t.Errorf("Verify failed: %v", err)
202 }
203
204 _, err = ParsePrivateKey(tt.PEMBytes)
205 if err == nil {
206 t.Fatalf("ParsePrivateKey succeeded, expected an error")
207 }
208
209 if err, ok := err.(*PassphraseMissingError); !ok {
210 t.Errorf("got error %q, want PassphraseMissingError", err)
211 } else if tt.IncludesPublicKey {
212 if err.PublicKey == nil {
213 t.Fatalf("expected PassphraseMissingError.PublicKey not to be nil")
214 }
215 got, want := err.PublicKey.Marshal(), s.PublicKey().Marshal()
216 if !bytes.Equal(got, want) {
217 t.Errorf("error field %q doesn't match signer public key %q", got, want)
218 }
219 }
220 })
Yasuhiro Matsumoto84f24df2017-06-23 19:03:27 +0900221 }
Yasuhiro Matsumotofea6c2c2017-02-02 15:10:04 +0900222}
223
Han-Wen Nienhuys4e058122013-09-26 11:17:52 -0400224func TestParseDSA(t *testing.T) {
Adam Langleyfa50e742014-04-09 13:57:52 -0700225 // We actually exercise the ParsePrivateKey codepath here, as opposed to
226 // using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
227 // uses.
228 s, err := ParsePrivateKey(testdata.PEMBytes["dsa"])
Han-Wen Nienhuys4e058122013-09-26 11:17:52 -0400229 if err != nil {
230 t.Fatalf("ParsePrivateKey returned error: %s", err)
231 }
232
233 data := []byte("sign me")
234 sig, err := s.Sign(rand.Reader, data)
235 if err != nil {
236 t.Fatalf("dsa.Sign: %v", err)
237 }
238
Adam Langleyfa50e742014-04-09 13:57:52 -0700239 if err := s.PublicKey().Verify(data, sig); err != nil {
240 t.Errorf("Verify failed: %v", err)
241 }
242}
243
244// Tests for authorized_keys parsing.
245
246// getTestKey returns a public key, and its base64 encoding.
247func getTestKey() (PublicKey, string) {
248 k := testPublicKeys["rsa"]
249
250 b := &bytes.Buffer{}
251 e := base64.NewEncoder(base64.StdEncoding, b)
252 e.Write(k.Marshal())
253 e.Close()
254
255 return k, b.String()
256}
257
258func TestMarshalParsePublicKey(t *testing.T) {
259 pub, pubSerialized := getTestKey()
260 line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized)
261
262 authKeys := MarshalAuthorizedKey(pub)
263 actualFields := strings.Fields(string(authKeys))
264 if len(actualFields) == 0 {
265 t.Fatalf("failed authKeys: %v", authKeys)
266 }
267
268 // drop the comment
269 expectedFields := strings.Fields(line)[0:2]
270
271 if !reflect.DeepEqual(actualFields, expectedFields) {
272 t.Errorf("got %v, expected %v", actualFields, expectedFields)
273 }
274
275 actPub, _, _, _, err := ParseAuthorizedKey([]byte(line))
276 if err != nil {
277 t.Fatalf("cannot parse %v: %v", line, err)
278 }
279 if !reflect.DeepEqual(actPub, pub) {
280 t.Errorf("got %v, expected %v", actPub, pub)
281 }
282}
283
Sami Pönkänen9334d732018-01-17 14:44:42 +0200284type testAuthResult struct {
Adam Langleyfa50e742014-04-09 13:57:52 -0700285 pubKey PublicKey
286 options []string
287 comments string
288 rest string
289 ok bool
290}
291
Sami Pönkänen9334d732018-01-17 14:44:42 +0200292func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []testAuthResult) {
Adam Langleyfa50e742014-04-09 13:57:52 -0700293 rest := authKeys
Sami Pönkänen9334d732018-01-17 14:44:42 +0200294 var values []testAuthResult
Adam Langleyfa50e742014-04-09 13:57:52 -0700295 for len(rest) > 0 {
Sami Pönkänen9334d732018-01-17 14:44:42 +0200296 var r testAuthResult
Adam Langleyfa50e742014-04-09 13:57:52 -0700297 var err error
298 r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
299 r.ok = (err == nil)
300 t.Log(err)
301 r.rest = string(rest)
302 values = append(values, r)
303 }
304
305 if !reflect.DeepEqual(values, expected) {
306 t.Errorf("got %#v, expected %#v", values, expected)
307 }
308}
309
310func TestAuthorizedKeyBasic(t *testing.T) {
311 pub, pubSerialized := getTestKey()
312 line := "ssh-rsa " + pubSerialized + " user@host"
313 testAuthorizedKeys(t, []byte(line),
Sami Pönkänen9334d732018-01-17 14:44:42 +0200314 []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700315 {pub, nil, "user@host", "", true},
316 })
317}
318
319func TestAuth(t *testing.T) {
320 pub, pubSerialized := getTestKey()
321 authWithOptions := []string{
322 `# comments to ignore before any keys...`,
323 ``,
324 `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`,
325 `# comments to ignore, along with a blank line`,
326 ``,
327 `env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`,
328 ``,
329 `# more comments, plus a invalid entry`,
330 `ssh-rsa data-that-will-not-parse user@host3`,
331 }
332 for _, eol := range []string{"\n", "\r\n"} {
333 authOptions := strings.Join(authWithOptions, eol)
334 rest2 := strings.Join(authWithOptions[3:], eol)
335 rest3 := strings.Join(authWithOptions[6:], eol)
Sami Pönkänen9334d732018-01-17 14:44:42 +0200336 testAuthorizedKeys(t, []byte(authOptions), []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700337 {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
338 {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
339 {nil, nil, "", "", false},
340 })
341 }
342}
343
344func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
345 pub, pubSerialized := getTestKey()
346 authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
Sami Pönkänen9334d732018-01-17 14:44:42 +0200347 testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700348 {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
349 })
350}
351
352func TestAuthWithQuotedCommaInEnv(t *testing.T) {
353 pub, pubSerialized := getTestKey()
354 authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
Sami Pönkänen9334d732018-01-17 14:44:42 +0200355 testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700356 {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
357 })
358}
359
360func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
361 pub, pubSerialized := getTestKey()
362 authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + ` user@host`)
363 authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
Sami Pönkänen9334d732018-01-17 14:44:42 +0200364 testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700365 {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
366 })
367
Sami Pönkänen9334d732018-01-17 14:44:42 +0200368 testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700369 {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
370 })
371}
372
373func TestAuthWithInvalidSpace(t *testing.T) {
374 _, pubSerialized := getTestKey()
375 authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
376#more to follow but still no valid keys`)
Sami Pönkänen9334d732018-01-17 14:44:42 +0200377 testAuthorizedKeys(t, []byte(authWithInvalidSpace), []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700378 {nil, nil, "", "", false},
379 })
380}
381
382func TestAuthWithMissingQuote(t *testing.T) {
383 pub, pubSerialized := getTestKey()
384 authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
385env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
386
Sami Pönkänen9334d732018-01-17 14:44:42 +0200387 testAuthorizedKeys(t, []byte(authWithMissingQuote), []testAuthResult{
Adam Langleyfa50e742014-04-09 13:57:52 -0700388 {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
389 })
390}
391
392func TestInvalidEntry(t *testing.T) {
393 authInvalid := []byte(`ssh-rsa`)
394 _, _, _, _, err := ParseAuthorizedKey(authInvalid)
395 if err == nil {
396 t.Errorf("got valid entry for %q", authInvalid)
Han-Wen Nienhuys4e058122013-09-26 11:17:52 -0400397 }
398}
Peter Moody3760e012015-12-23 13:51:54 -0800399
400var knownHostsParseTests = []struct {
Emmanuel Odekea20de3f2016-09-23 01:39:13 -0700401 input string
402 err string
Peter Moody3760e012015-12-23 13:51:54 -0800403
Emmanuel Odekea20de3f2016-09-23 01:39:13 -0700404 marker string
405 comment string
406 hosts []string
407 rest string
408}{
Peter Moody3760e012015-12-23 13:51:54 -0800409 {
410 "",
411 "EOF",
412
413 "", "", nil, "",
414 },
415 {
416 "# Just a comment",
417 "EOF",
418
419 "", "", nil, "",
420 },
421 {
422 " \t ",
423 "EOF",
424
425 "", "", nil, "",
426 },
427 {
428 "localhost ssh-rsa {RSAPUB}",
429 "",
430
431 "", "", []string{"localhost"}, "",
432 },
433 {
434 "localhost\tssh-rsa {RSAPUB}",
435 "",
436
437 "", "", []string{"localhost"}, "",
438 },
439 {
440 "localhost\tssh-rsa {RSAPUB}\tcomment comment",
441 "",
442
443 "", "comment comment", []string{"localhost"}, "",
444 },
445 {
446 "localhost\tssh-rsa {RSAPUB}\tcomment comment\n",
447 "",
448
449 "", "comment comment", []string{"localhost"}, "",
450 },
451 {
452 "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\n",
453 "",
454
455 "", "comment comment", []string{"localhost"}, "",
456 },
457 {
458 "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\nnext line",
459 "",
460
461 "", "comment comment", []string{"localhost"}, "next line",
462 },
463 {
464 "localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment",
465 "",
466
Emmanuel Odekea20de3f2016-09-23 01:39:13 -0700467 "", "comment comment", []string{"localhost", "[host2:123]"}, "",
Peter Moody3760e012015-12-23 13:51:54 -0800468 },
469 {
470 "@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}",
471 "",
472
Emmanuel Odekea20de3f2016-09-23 01:39:13 -0700473 "marker", "", []string{"localhost", "[host2:123]"}, "",
Peter Moody3760e012015-12-23 13:51:54 -0800474 },
475 {
476 "@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
477 "short read",
478
479 "", "", nil, "",
480 },
481}
482
483func TestKnownHostsParsing(t *testing.T) {
484 rsaPub, rsaPubSerialized := getTestKey()
485
486 for i, test := range knownHostsParseTests {
487 var expectedKey PublicKey
488 const rsaKeyToken = "{RSAPUB}"
489
490 input := test.input
491 if strings.Contains(input, rsaKeyToken) {
492 expectedKey = rsaPub
493 input = strings.Replace(test.input, rsaKeyToken, rsaPubSerialized, -1)
494 }
495
496 marker, hosts, pubKey, comment, rest, err := ParseKnownHosts([]byte(input))
497 if err != nil {
498 if len(test.err) == 0 {
499 t.Errorf("#%d: unexpectedly failed with %q", i, err)
500 } else if !strings.Contains(err.Error(), test.err) {
501 t.Errorf("#%d: expected error containing %q, but got %q", i, test.err, err)
502 }
503 continue
504 } else if len(test.err) != 0 {
505 t.Errorf("#%d: succeeded but expected error including %q", i, test.err)
506 continue
507 }
508
509 if !reflect.DeepEqual(expectedKey, pubKey) {
510 t.Errorf("#%d: expected key %#v, but got %#v", i, expectedKey, pubKey)
511 }
512
513 if marker != test.marker {
514 t.Errorf("#%d: expected marker %q, but got %q", i, test.marker, marker)
515 }
516
517 if comment != test.comment {
518 t.Errorf("#%d: expected comment %q, but got %q", i, test.comment, comment)
519 }
520
521 if !reflect.DeepEqual(test.hosts, hosts) {
522 t.Errorf("#%d: expected hosts %#v, but got %#v", i, test.hosts, hosts)
523 }
524
525 if rest := string(rest); rest != test.rest {
526 t.Errorf("#%d: expected remaining input to be %q, but got %q", i, test.rest, rest)
527 }
528 }
529}
Ryuzo Yamamotoede567c2016-11-04 15:41:44 -0400530
531func TestFingerprintLegacyMD5(t *testing.T) {
532 pub, _ := getTestKey()
533 fingerprint := FingerprintLegacyMD5(pub)
534 want := "fb:61:6d:1a:e3:f0:95:45:3c:a0:79:be:4a:93:63:66" // ssh-keygen -lf -E md5 rsa
535 if fingerprint != want {
536 t.Errorf("got fingerprint %q want %q", fingerprint, want)
537 }
538}
539
540func TestFingerprintSHA256(t *testing.T) {
541 pub, _ := getTestKey()
542 fingerprint := FingerprintSHA256(pub)
543 want := "SHA256:Anr3LjZK8YVpjrxu79myrW9Hrb/wpcMNpVvTq/RcBm8" // ssh-keygen -lf rsa
544 if fingerprint != want {
545 t.Errorf("got fingerprint %q want %q", fingerprint, want)
546 }
547}
Adam Langley0709b302018-08-31 15:38:59 -0700548
549func TestInvalidKeys(t *testing.T) {
550 keyTypes := []string{
551 "RSA PRIVATE KEY",
552 "PRIVATE KEY",
553 "EC PRIVATE KEY",
554 "DSA PRIVATE KEY",
555 "OPENSSH PRIVATE KEY",
556 }
557
558 for _, keyType := range keyTypes {
559 for _, dataLen := range []int{0, 1, 2, 5, 10, 20} {
560 data := make([]byte, dataLen)
561 if _, err := io.ReadFull(rand.Reader, data); err != nil {
562 t.Fatal(err)
563 }
564
565 var buf bytes.Buffer
566 pem.Encode(&buf, &pem.Block{
567 Type: keyType,
568 Bytes: data,
569 })
570
571 // This test is just to ensure that the function
572 // doesn't panic so the return value is ignored.
573 ParseRawPrivateKey(buf.Bytes())
574 }
575 }
576}
Sebastian Kinne86a70502019-11-19 16:30:15 -0800577
578func TestSKKeys(t *testing.T) {
579 for _, d := range testdata.SKData {
580 pk, _, _, _, err := ParseAuthorizedKey(d.PubKey)
581 if err != nil {
582 t.Fatalf("parseAuthorizedKey returned error: %v", err)
583 }
584
585 sigBuf := make([]byte, hex.DecodedLen(len(d.HexSignature)))
586 if _, err := hex.Decode(sigBuf, d.HexSignature); err != nil {
587 t.Fatalf("hex.Decode() failed: %v", err)
588 }
589
590 dataBuf := make([]byte, hex.DecodedLen(len(d.HexData)))
591 if _, err := hex.Decode(dataBuf, d.HexData); err != nil {
592 t.Fatalf("hex.Decode() failed: %v", err)
593 }
594
595 sig, _, ok := parseSignature(sigBuf)
596 if !ok {
597 t.Fatalf("parseSignature(%v) failed", sigBuf)
598 }
599
600 // Test that good data and signature pass verification
601 if err := pk.Verify(dataBuf, sig); err != nil {
602 t.Errorf("%s: PublicKey.Verify(%v, %v) failed: %v", d.Name, dataBuf, sig, err)
603 }
604
605 // Invalid data being passed in
606 invalidData := []byte("INVALID DATA")
607 if err := pk.Verify(invalidData, sig); err == nil {
608 t.Errorf("%s with invalid data: PublicKey.Verify(%v, %v) passed unexpectedly", d.Name, invalidData, sig)
609 }
610
611 // Change byte in blob to corrup signature
612 sig.Blob[5] = byte('A')
613 // Corrupted data being passed in
614 if err := pk.Verify(dataBuf, sig); err == nil {
615 t.Errorf("%s with corrupted signature: PublicKey.Verify(%v, %v) passed unexpectedly", d.Name, dataBuf, sig)
616 }
617 }
618}