OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / crypto / ssh / keys_test.go
1 // 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
5 package ssh
6
7 import (
8         "bytes"
9         "crypto/dsa"
10         "crypto/ecdsa"
11         "crypto/elliptic"
12         "crypto/rand"
13         "crypto/rsa"
14         "crypto/x509"
15         "encoding/base64"
16         "fmt"
17         "reflect"
18         "strings"
19         "testing"
20
21         "golang.org/x/crypto/ed25519"
22         "golang.org/x/crypto/ssh/testdata"
23 )
24
25 func rawKey(pub PublicKey) interface{} {
26         switch k := pub.(type) {
27         case *rsaPublicKey:
28                 return (*rsa.PublicKey)(k)
29         case *dsaPublicKey:
30                 return (*dsa.PublicKey)(k)
31         case *ecdsaPublicKey:
32                 return (*ecdsa.PublicKey)(k)
33         case ed25519PublicKey:
34                 return (ed25519.PublicKey)(k)
35         case *Certificate:
36                 return k
37         }
38         panic("unknown key type")
39 }
40
41 func TestKeyMarshalParse(t *testing.T) {
42         for _, priv := range testSigners {
43                 pub := priv.PublicKey()
44                 roundtrip, err := ParsePublicKey(pub.Marshal())
45                 if err != nil {
46                         t.Errorf("ParsePublicKey(%T): %v", pub, err)
47                 }
48
49                 k1 := rawKey(pub)
50                 k2 := rawKey(roundtrip)
51
52                 if !reflect.DeepEqual(k1, k2) {
53                         t.Errorf("got %#v in roundtrip, want %#v", k2, k1)
54                 }
55         }
56 }
57
58 func TestUnsupportedCurves(t *testing.T) {
59         raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
60         if err != nil {
61                 t.Fatalf("GenerateKey: %v", err)
62         }
63
64         if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P-256") {
65                 t.Fatalf("NewPrivateKey should not succeed with P-224, got: %v", err)
66         }
67
68         if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P-256") {
69                 t.Fatalf("NewPublicKey should not succeed with P-224, got: %v", err)
70         }
71 }
72
73 func TestNewPublicKey(t *testing.T) {
74         for _, k := range testSigners {
75                 raw := rawKey(k.PublicKey())
76                 // Skip certificates, as NewPublicKey does not support them.
77                 if _, ok := raw.(*Certificate); ok {
78                         continue
79                 }
80                 pub, err := NewPublicKey(raw)
81                 if err != nil {
82                         t.Errorf("NewPublicKey(%#v): %v", raw, err)
83                 }
84                 if !reflect.DeepEqual(k.PublicKey(), pub) {
85                         t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey())
86                 }
87         }
88 }
89
90 func TestKeySignVerify(t *testing.T) {
91         for _, priv := range testSigners {
92                 pub := priv.PublicKey()
93
94                 data := []byte("sign me")
95                 sig, err := priv.Sign(rand.Reader, data)
96                 if err != nil {
97                         t.Fatalf("Sign(%T): %v", priv, err)
98                 }
99
100                 if err := pub.Verify(data, sig); err != nil {
101                         t.Errorf("publicKey.Verify(%T): %v", priv, err)
102                 }
103                 sig.Blob[5]++
104                 if err := pub.Verify(data, sig); err == nil {
105                         t.Errorf("publicKey.Verify on broken sig did not fail")
106                 }
107         }
108 }
109
110 func TestParseRSAPrivateKey(t *testing.T) {
111         key := testPrivateKeys["rsa"]
112
113         rsa, ok := key.(*rsa.PrivateKey)
114         if !ok {
115                 t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
116         }
117
118         if err := rsa.Validate(); err != nil {
119                 t.Errorf("Validate: %v", err)
120         }
121 }
122
123 func TestParseECPrivateKey(t *testing.T) {
124         key := testPrivateKeys["ecdsa"]
125
126         ecKey, ok := key.(*ecdsa.PrivateKey)
127         if !ok {
128                 t.Fatalf("got %T, want *ecdsa.PrivateKey", ecKey)
129         }
130
131         if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
132                 t.Fatalf("public key does not validate.")
133         }
134 }
135
136 // See Issue https://github.com/golang/go/issues/6650.
137 func TestParseEncryptedPrivateKeysFails(t *testing.T) {
138         const wantSubstring = "encrypted"
139         for i, tt := range testdata.PEMEncryptedKeys {
140                 _, err := ParsePrivateKey(tt.PEMBytes)
141                 if err == nil {
142                         t.Errorf("#%d key %s: ParsePrivateKey successfully parsed, expected an error", i, tt.Name)
143                         continue
144                 }
145
146                 if !strings.Contains(err.Error(), wantSubstring) {
147                         t.Errorf("#%d key %s: got error %q, want substring %q", i, tt.Name, err, wantSubstring)
148                 }
149         }
150 }
151
152 // Parse encrypted private keys with passphrase
153 func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) {
154         data := []byte("sign me")
155         for _, tt := range testdata.PEMEncryptedKeys {
156                 s, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte(tt.EncryptionKey))
157                 if err != nil {
158                         t.Fatalf("ParsePrivateKeyWithPassphrase returned error: %s", err)
159                         continue
160                 }
161                 sig, err := s.Sign(rand.Reader, data)
162                 if err != nil {
163                         t.Fatalf("dsa.Sign: %v", err)
164                 }
165                 if err := s.PublicKey().Verify(data, sig); err != nil {
166                         t.Errorf("Verify failed: %v", err)
167                 }
168         }
169
170         tt := testdata.PEMEncryptedKeys[0]
171         _, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte("incorrect"))
172         if err != x509.IncorrectPasswordError {
173                 t.Fatalf("got %v want IncorrectPasswordError", err)
174         }
175 }
176
177 func TestParseDSA(t *testing.T) {
178         // We actually exercise the ParsePrivateKey codepath here, as opposed to
179         // using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
180         // uses.
181         s, err := ParsePrivateKey(testdata.PEMBytes["dsa"])
182         if err != nil {
183                 t.Fatalf("ParsePrivateKey returned error: %s", err)
184         }
185
186         data := []byte("sign me")
187         sig, err := s.Sign(rand.Reader, data)
188         if err != nil {
189                 t.Fatalf("dsa.Sign: %v", err)
190         }
191
192         if err := s.PublicKey().Verify(data, sig); err != nil {
193                 t.Errorf("Verify failed: %v", err)
194         }
195 }
196
197 // Tests for authorized_keys parsing.
198
199 // getTestKey returns a public key, and its base64 encoding.
200 func getTestKey() (PublicKey, string) {
201         k := testPublicKeys["rsa"]
202
203         b := &bytes.Buffer{}
204         e := base64.NewEncoder(base64.StdEncoding, b)
205         e.Write(k.Marshal())
206         e.Close()
207
208         return k, b.String()
209 }
210
211 func TestMarshalParsePublicKey(t *testing.T) {
212         pub, pubSerialized := getTestKey()
213         line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized)
214
215         authKeys := MarshalAuthorizedKey(pub)
216         actualFields := strings.Fields(string(authKeys))
217         if len(actualFields) == 0 {
218                 t.Fatalf("failed authKeys: %v", authKeys)
219         }
220
221         // drop the comment
222         expectedFields := strings.Fields(line)[0:2]
223
224         if !reflect.DeepEqual(actualFields, expectedFields) {
225                 t.Errorf("got %v, expected %v", actualFields, expectedFields)
226         }
227
228         actPub, _, _, _, err := ParseAuthorizedKey([]byte(line))
229         if err != nil {
230                 t.Fatalf("cannot parse %v: %v", line, err)
231         }
232         if !reflect.DeepEqual(actPub, pub) {
233                 t.Errorf("got %v, expected %v", actPub, pub)
234         }
235 }
236
237 type authResult struct {
238         pubKey   PublicKey
239         options  []string
240         comments string
241         rest     string
242         ok       bool
243 }
244
245 func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) {
246         rest := authKeys
247         var values []authResult
248         for len(rest) > 0 {
249                 var r authResult
250                 var err error
251                 r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
252                 r.ok = (err == nil)
253                 t.Log(err)
254                 r.rest = string(rest)
255                 values = append(values, r)
256         }
257
258         if !reflect.DeepEqual(values, expected) {
259                 t.Errorf("got %#v, expected %#v", values, expected)
260         }
261 }
262
263 func TestAuthorizedKeyBasic(t *testing.T) {
264         pub, pubSerialized := getTestKey()
265         line := "ssh-rsa " + pubSerialized + " user@host"
266         testAuthorizedKeys(t, []byte(line),
267                 []authResult{
268                         {pub, nil, "user@host", "", true},
269                 })
270 }
271
272 func TestAuth(t *testing.T) {
273         pub, pubSerialized := getTestKey()
274         authWithOptions := []string{
275                 `# comments to ignore before any keys...`,
276                 ``,
277                 `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`,
278                 `# comments to ignore, along with a blank line`,
279                 ``,
280                 `env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`,
281                 ``,
282                 `# more comments, plus a invalid entry`,
283                 `ssh-rsa data-that-will-not-parse user@host3`,
284         }
285         for _, eol := range []string{"\n", "\r\n"} {
286                 authOptions := strings.Join(authWithOptions, eol)
287                 rest2 := strings.Join(authWithOptions[3:], eol)
288                 rest3 := strings.Join(authWithOptions[6:], eol)
289                 testAuthorizedKeys(t, []byte(authOptions), []authResult{
290                         {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
291                         {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
292                         {nil, nil, "", "", false},
293                 })
294         }
295 }
296
297 func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
298         pub, pubSerialized := getTestKey()
299         authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
300         testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{
301                 {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
302         })
303 }
304
305 func TestAuthWithQuotedCommaInEnv(t *testing.T) {
306         pub, pubSerialized := getTestKey()
307         authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + `   user@host`)
308         testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{
309                 {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
310         })
311 }
312
313 func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
314         pub, pubSerialized := getTestKey()
315         authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + `   user@host`)
316         authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
317         testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{
318                 {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
319         })
320
321         testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{
322                 {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
323         })
324 }
325
326 func TestAuthWithInvalidSpace(t *testing.T) {
327         _, pubSerialized := getTestKey()
328         authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
329 #more to follow but still no valid keys`)
330         testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{
331                 {nil, nil, "", "", false},
332         })
333 }
334
335 func TestAuthWithMissingQuote(t *testing.T) {
336         pub, pubSerialized := getTestKey()
337         authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
338 env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
339
340         testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{
341                 {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
342         })
343 }
344
345 func TestInvalidEntry(t *testing.T) {
346         authInvalid := []byte(`ssh-rsa`)
347         _, _, _, _, err := ParseAuthorizedKey(authInvalid)
348         if err == nil {
349                 t.Errorf("got valid entry for %q", authInvalid)
350         }
351 }
352
353 var knownHostsParseTests = []struct {
354         input string
355         err   string
356
357         marker  string
358         comment string
359         hosts   []string
360         rest    string
361 }{
362         {
363                 "",
364                 "EOF",
365
366                 "", "", nil, "",
367         },
368         {
369                 "# Just a comment",
370                 "EOF",
371
372                 "", "", nil, "",
373         },
374         {
375                 "   \t   ",
376                 "EOF",
377
378                 "", "", nil, "",
379         },
380         {
381                 "localhost ssh-rsa {RSAPUB}",
382                 "",
383
384                 "", "", []string{"localhost"}, "",
385         },
386         {
387                 "localhost\tssh-rsa {RSAPUB}",
388                 "",
389
390                 "", "", []string{"localhost"}, "",
391         },
392         {
393                 "localhost\tssh-rsa {RSAPUB}\tcomment comment",
394                 "",
395
396                 "", "comment comment", []string{"localhost"}, "",
397         },
398         {
399                 "localhost\tssh-rsa {RSAPUB}\tcomment comment\n",
400                 "",
401
402                 "", "comment comment", []string{"localhost"}, "",
403         },
404         {
405                 "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\n",
406                 "",
407
408                 "", "comment comment", []string{"localhost"}, "",
409         },
410         {
411                 "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\nnext line",
412                 "",
413
414                 "", "comment comment", []string{"localhost"}, "next line",
415         },
416         {
417                 "localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment",
418                 "",
419
420                 "", "comment comment", []string{"localhost", "[host2:123]"}, "",
421         },
422         {
423                 "@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}",
424                 "",
425
426                 "marker", "", []string{"localhost", "[host2:123]"}, "",
427         },
428         {
429                 "@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
430                 "short read",
431
432                 "", "", nil, "",
433         },
434 }
435
436 func TestKnownHostsParsing(t *testing.T) {
437         rsaPub, rsaPubSerialized := getTestKey()
438
439         for i, test := range knownHostsParseTests {
440                 var expectedKey PublicKey
441                 const rsaKeyToken = "{RSAPUB}"
442
443                 input := test.input
444                 if strings.Contains(input, rsaKeyToken) {
445                         expectedKey = rsaPub
446                         input = strings.Replace(test.input, rsaKeyToken, rsaPubSerialized, -1)
447                 }
448
449                 marker, hosts, pubKey, comment, rest, err := ParseKnownHosts([]byte(input))
450                 if err != nil {
451                         if len(test.err) == 0 {
452                                 t.Errorf("#%d: unexpectedly failed with %q", i, err)
453                         } else if !strings.Contains(err.Error(), test.err) {
454                                 t.Errorf("#%d: expected error containing %q, but got %q", i, test.err, err)
455                         }
456                         continue
457                 } else if len(test.err) != 0 {
458                         t.Errorf("#%d: succeeded but expected error including %q", i, test.err)
459                         continue
460                 }
461
462                 if !reflect.DeepEqual(expectedKey, pubKey) {
463                         t.Errorf("#%d: expected key %#v, but got %#v", i, expectedKey, pubKey)
464                 }
465
466                 if marker != test.marker {
467                         t.Errorf("#%d: expected marker %q, but got %q", i, test.marker, marker)
468                 }
469
470                 if comment != test.comment {
471                         t.Errorf("#%d: expected comment %q, but got %q", i, test.comment, comment)
472                 }
473
474                 if !reflect.DeepEqual(test.hosts, hosts) {
475                         t.Errorf("#%d: expected hosts %#v, but got %#v", i, test.hosts, hosts)
476                 }
477
478                 if rest := string(rest); rest != test.rest {
479                         t.Errorf("#%d: expected remaining input to be %q, but got %q", i, test.rest, rest)
480                 }
481         }
482 }
483
484 func TestFingerprintLegacyMD5(t *testing.T) {
485         pub, _ := getTestKey()
486         fingerprint := FingerprintLegacyMD5(pub)
487         want := "fb:61:6d:1a:e3:f0:95:45:3c:a0:79:be:4a:93:63:66" // ssh-keygen -lf -E md5 rsa
488         if fingerprint != want {
489                 t.Errorf("got fingerprint %q want %q", fingerprint, want)
490         }
491 }
492
493 func TestFingerprintSHA256(t *testing.T) {
494         pub, _ := getTestKey()
495         fingerprint := FingerprintSHA256(pub)
496         want := "SHA256:Anr3LjZK8YVpjrxu79myrW9Hrb/wpcMNpVvTq/RcBm8" // ssh-keygen -lf rsa
497         if fingerprint != want {
498                 t.Errorf("got fingerprint %q want %q", fingerprint, want)
499         }
500 }