OLD | NEW |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package ssh | 5 package ssh |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "crypto" | |
10 "crypto/dsa" | 9 "crypto/dsa" |
11 "crypto/rsa" | |
12 "crypto/x509" | |
13 "encoding/pem" | |
14 "errors" | |
15 "io" | 10 "io" |
16 "io/ioutil" | 11 "io/ioutil" |
17 "math/big" | 12 "math/big" |
18 "strings" | 13 "strings" |
19 "testing" | 14 "testing" |
20 | 15 |
21 _ "crypto/sha1" | 16 _ "crypto/sha1" |
22 ) | 17 ) |
23 | 18 |
24 // private key for mock server | 19 // private key for mock server |
(...skipping 30 matching lines...) Expand all Loading... |
55 r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ | 50 r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ |
56 tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC | 51 tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC |
57 nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW | 52 nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW |
58 2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB | 53 2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB |
59 y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr | 54 y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr |
60 rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg== | 55 rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg== |
61 -----END RSA PRIVATE KEY-----` | 56 -----END RSA PRIVATE KEY-----` |
62 | 57 |
63 // keychain implements the ClientKeyring interface | 58 // keychain implements the ClientKeyring interface |
64 type keychain struct { | 59 type keychain struct { |
65 » keys []interface{} | 60 » keys []PrivateKey |
66 } | 61 } |
67 | 62 |
68 func (k *keychain) Key(i int) (PublicKey, error) { | 63 func (k *keychain) Key(i int) (PublicKey, error) { |
69 if i < 0 || i >= len(k.keys) { | 64 if i < 0 || i >= len(k.keys) { |
70 return nil, nil | 65 return nil, nil |
71 } | 66 } |
72 » switch key := k.keys[i].(type) { | 67 |
73 » case *rsa.PrivateKey: | 68 » return k.keys[i].PublicKey(), nil |
74 » » return NewRSAPublicKey(&key.PublicKey), nil | |
75 » case *dsa.PrivateKey: | |
76 » » return NewDSAPublicKey(&key.PublicKey), nil | |
77 » } | |
78 » panic("unknown key type") | |
79 } | 69 } |
80 | 70 |
81 func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err err
or) { | 71 func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err err
or) { |
82 » hashFunc := crypto.SHA1 | 72 » return k.keys[i].Sign(rand, data) |
83 » h := hashFunc.New() | 73 } |
84 » h.Write(data) | 74 |
85 » digest := h.Sum(nil) | 75 func (k *keychain) add(key PrivateKey) { |
86 » switch key := k.keys[i].(type) { | 76 » k.keys = append(k.keys, key) |
87 » case *rsa.PrivateKey: | |
88 » » return rsa.SignPKCS1v15(rand, key, hashFunc, digest) | |
89 » } | |
90 » return nil, errors.New("ssh: unknown key type") | |
91 } | 77 } |
92 | 78 |
93 func (k *keychain) loadPEM(file string) error { | 79 func (k *keychain) loadPEM(file string) error { |
94 buf, err := ioutil.ReadFile(file) | 80 buf, err := ioutil.ReadFile(file) |
95 if err != nil { | 81 if err != nil { |
96 return err | 82 return err |
97 } | 83 } |
98 » block, _ := pem.Decode(buf) | 84 » key, err := ParsePrivateKey(buf) |
99 » if block == nil { | |
100 » » return errors.New("ssh: no key found") | |
101 » } | |
102 » r, err := x509.ParsePKCS1PrivateKey(block.Bytes) | |
103 if err != nil { | 85 if err != nil { |
104 return err | 86 return err |
105 } | 87 } |
106 » k.keys = append(k.keys, r) | 88 » k.add(key) |
107 return nil | 89 return nil |
108 } | 90 } |
109 | 91 |
110 // password implements the ClientPassword interface | 92 // password implements the ClientPassword interface |
111 type password string | 93 type password string |
112 | 94 |
113 func (p password) Password(user string) (string, error) { | 95 func (p password) Password(user string) (string, error) { |
114 return string(p), nil | 96 return string(p), nil |
115 } | 97 } |
116 | 98 |
117 type keyboardInteractive map[string]string | 99 type keyboardInteractive map[string]string |
118 | 100 |
119 func (cr *keyboardInteractive) Challenge(user string, instruction string, questi
ons []string, echos []bool) ([]string, error) { | 101 func (cr *keyboardInteractive) Challenge(user string, instruction string, questi
ons []string, echos []bool) ([]string, error) { |
120 var answers []string | 102 var answers []string |
121 for _, q := range questions { | 103 for _, q := range questions { |
122 answers = append(answers, (*cr)[q]) | 104 answers = append(answers, (*cr)[q]) |
123 } | 105 } |
124 return answers, nil | 106 return answers, nil |
125 } | 107 } |
126 | 108 |
127 // reused internally by tests | 109 // reused internally by tests |
128 var ( | 110 var ( |
129 » rsakey *rsa.PrivateKey | 111 » rsaKey PrivateKey |
130 » dsakey *dsa.PrivateKey | 112 » dsaKey PrivateKey |
131 clientKeychain = new(keychain) | 113 clientKeychain = new(keychain) |
132 clientPassword = password("tiger") | 114 clientPassword = password("tiger") |
133 serverConfig = &ServerConfig{ | 115 serverConfig = &ServerConfig{ |
134 PasswordCallback: func(conn *ServerConn, user, pass string) bool
{ | 116 PasswordCallback: func(conn *ServerConn, user, pass string) bool
{ |
135 return user == "testuser" && pass == string(clientPasswo
rd) | 117 return user == "testuser" && pass == string(clientPasswo
rd) |
136 }, | 118 }, |
137 PublicKeyCallback: func(conn *ServerConn, user, algo string, pub
key []byte) bool { | 119 PublicKeyCallback: func(conn *ServerConn, user, algo string, pub
key []byte) bool { |
138 » » » rsaKey := &clientKeychain.keys[0].(*rsa.PrivateKey).Publ
icKey | 120 » » » key := clientKeychain.keys[0].PublicKey() |
139 » » » key := NewRSAPublicKey(rsaKey) | |
140 expected := MarshalPublicKey(key) | 121 expected := MarshalPublicKey(key) |
141 algoname := key.PublicKeyAlgo() | 122 algoname := key.PublicKeyAlgo() |
142 return user == "testuser" && algo == algoname && bytes.E
qual(pubkey, expected) | 123 return user == "testuser" && algo == algoname && bytes.E
qual(pubkey, expected) |
143 }, | 124 }, |
144 KeyboardInteractiveCallback: func(conn *ServerConn, user string,
client ClientKeyboardInteractive) bool { | 125 KeyboardInteractiveCallback: func(conn *ServerConn, user string,
client ClientKeyboardInteractive) bool { |
145 ans, err := client.Challenge("user", | 126 ans, err := client.Challenge("user", |
146 "instruction", | 127 "instruction", |
147 []string{"question1", "question2"}, | 128 []string{"question1", "question2"}, |
148 []bool{true, true}) | 129 []bool{true, true}) |
149 if err != nil { | 130 if err != nil { |
150 return false | 131 return false |
151 } | 132 } |
152 ok := user == "testuser" && ans[0] == "answer1" && ans[1
] == "answer2" | 133 ok := user == "testuser" && ans[0] == "answer1" && ans[1
] == "answer2" |
153 client.Challenge("user", "motd", nil, nil) | 134 client.Challenge("user", "motd", nil, nil) |
154 return ok | 135 return ok |
155 }, | 136 }, |
156 } | 137 } |
157 ) | 138 ) |
158 | 139 |
159 func init() { | 140 func init() { |
160 » if err := serverConfig.SetRSAPrivateKey([]byte(testServerPrivateKey)); e
rr != nil { | 141 » var err error |
| 142 » rsaKey, err = ParsePrivateKey([]byte(testServerPrivateKey)) |
| 143 » if err != nil { |
161 panic("unable to set private key: " + err.Error()) | 144 panic("unable to set private key: " + err.Error()) |
162 } | 145 } |
| 146 rawDSAKey := new(dsa.PrivateKey) |
163 | 147 |
164 » block, _ := pem.Decode([]byte(testClientPrivateKey)) | 148 » // taken from crypto/dsa/dsa_test.go |
165 » rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes) | 149 » rawDSAKey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF6
3CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65D
A5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F4268
5EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16) |
| 150 » rawDSAKey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A
1F422B9C1", 16) |
| 151 » rawDSAKey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD06
57CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B9
5DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF
89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16) |
| 152 » rawDSAKey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F
38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72
568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB6
94AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16) |
| 153 » rawDSAKey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0
BCDBEE91A", 16) |
166 | 154 |
167 » clientKeychain.keys = append(clientKeychain.keys, rsakey) | 155 » dsaKey, err = NewPrivateKey(rawDSAKey) |
168 » dsakey = new(dsa.PrivateKey) | 156 » if err != nil { |
169 » // taken from crypto/dsa/dsa_test.go | 157 » » panic("NewPrivateKey: " + err.Error()) |
170 » dsakey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA
52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA56
84BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EB
B2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16) | 158 » } |
171 » dsakey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F4
22B9C1", 16) | 159 » clientKeychain.add(rsaKey) |
172 » dsakey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657C
C0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA
4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D
3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16) | 160 » serverConfig.AddHostKey(rsaKey) |
173 » dsakey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A
23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568
944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694A
B1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16) | |
174 » dsakey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCD
BEE91A", 16) | |
175 } | 161 } |
176 | 162 |
177 // newMockAuthServer creates a new Server bound to | 163 // newMockAuthServer creates a new Server bound to |
178 // the loopback interface. The server exits after | 164 // the loopback interface. The server exits after |
179 // processing one handshake. | 165 // processing one handshake. |
180 func newMockAuthServer(t *testing.T) string { | 166 func newMockAuthServer(t *testing.T) string { |
181 l, err := Listen("tcp", "127.0.0.1:0", serverConfig) | 167 l, err := Listen("tcp", "127.0.0.1:0", serverConfig) |
182 if err != nil { | 168 if err != nil { |
183 t.Fatalf("unable to newMockAuthServer: %s", err) | 169 t.Fatalf("unable to newMockAuthServer: %s", err) |
184 } | 170 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 c, err := Dial("tcp", newMockAuthServer(t), config) | 266 c, err := Dial("tcp", newMockAuthServer(t), config) |
281 if err == nil { | 267 if err == nil { |
282 c.Close() | 268 c.Close() |
283 t.Fatalf("wrong answers should not have authenticated with Keybo
ardInteractive") | 269 t.Fatalf("wrong answers should not have authenticated with Keybo
ardInteractive") |
284 } | 270 } |
285 } | 271 } |
286 | 272 |
287 // the mock server will only authenticate ssh-rsa keys | 273 // the mock server will only authenticate ssh-rsa keys |
288 func TestClientAuthInvalidPublicKey(t *testing.T) { | 274 func TestClientAuthInvalidPublicKey(t *testing.T) { |
289 kc := new(keychain) | 275 kc := new(keychain) |
290 » kc.keys = append(kc.keys, dsakey) | 276 |
| 277 » kc.add(dsaKey) |
291 config := &ClientConfig{ | 278 config := &ClientConfig{ |
292 User: "testuser", | 279 User: "testuser", |
293 Auth: []ClientAuth{ | 280 Auth: []ClientAuth{ |
294 ClientAuthKeyring(kc), | 281 ClientAuthKeyring(kc), |
295 }, | 282 }, |
296 } | 283 } |
297 | 284 |
298 c, err := Dial("tcp", newMockAuthServer(t), config) | 285 c, err := Dial("tcp", newMockAuthServer(t), config) |
299 if err == nil { | 286 if err == nil { |
300 c.Close() | 287 c.Close() |
301 t.Fatalf("dsa private key should not have authenticated with rsa
public key") | 288 t.Fatalf("dsa private key should not have authenticated with rsa
public key") |
302 } | 289 } |
303 } | 290 } |
304 | 291 |
305 // the client should authenticate with the second key | 292 // the client should authenticate with the second key |
306 func TestClientAuthRSAandDSA(t *testing.T) { | 293 func TestClientAuthRSAandDSA(t *testing.T) { |
307 kc := new(keychain) | 294 kc := new(keychain) |
308 » kc.keys = append(kc.keys, dsakey, rsakey) | 295 » kc.add(dsaKey) |
| 296 » kc.add(rsaKey) |
309 config := &ClientConfig{ | 297 config := &ClientConfig{ |
310 User: "testuser", | 298 User: "testuser", |
311 Auth: []ClientAuth{ | 299 Auth: []ClientAuth{ |
312 ClientAuthKeyring(kc), | 300 ClientAuthKeyring(kc), |
313 }, | 301 }, |
314 } | 302 } |
315 c, err := Dial("tcp", newMockAuthServer(t), config) | 303 c, err := Dial("tcp", newMockAuthServer(t), config) |
316 if err != nil { | 304 if err != nil { |
317 t.Fatalf("client could not authenticate with rsa key: %v", err) | 305 t.Fatalf("client could not authenticate with rsa key: %v", err) |
318 } | 306 } |
319 c.Close() | 307 c.Close() |
320 } | 308 } |
321 | 309 |
322 func TestClientHMAC(t *testing.T) { | 310 func TestClientHMAC(t *testing.T) { |
323 kc := new(keychain) | 311 kc := new(keychain) |
324 » kc.keys = append(kc.keys, rsakey) | 312 » kc.add(rsaKey) |
325 for _, mac := range DefaultMACOrder { | 313 for _, mac := range DefaultMACOrder { |
326 config := &ClientConfig{ | 314 config := &ClientConfig{ |
327 User: "testuser", | 315 User: "testuser", |
328 Auth: []ClientAuth{ | 316 Auth: []ClientAuth{ |
329 ClientAuthKeyring(kc), | 317 ClientAuthKeyring(kc), |
330 }, | 318 }, |
331 Crypto: CryptoConfig{ | 319 Crypto: CryptoConfig{ |
332 MACs: []string{mac}, | 320 MACs: []string{mac}, |
333 }, | 321 }, |
334 } | 322 } |
335 c, err := Dial("tcp", newMockAuthServer(t), config) | 323 c, err := Dial("tcp", newMockAuthServer(t), config) |
336 if err != nil { | 324 if err != nil { |
337 t.Fatalf("client could not authenticate with mac algo %s
: %v", mac, err) | 325 t.Fatalf("client could not authenticate with mac algo %s
: %v", mac, err) |
338 } | 326 } |
339 c.Close() | 327 c.Close() |
340 } | 328 } |
341 } | 329 } |
342 | 330 |
343 // issue 4285. | 331 // issue 4285. |
344 func TestClientUnsupportedCipher(t *testing.T) { | 332 func TestClientUnsupportedCipher(t *testing.T) { |
345 kc := new(keychain) | 333 kc := new(keychain) |
346 kc.keys = append(kc.keys, rsakey) | |
347 config := &ClientConfig{ | 334 config := &ClientConfig{ |
348 User: "testuser", | 335 User: "testuser", |
349 Auth: []ClientAuth{ | 336 Auth: []ClientAuth{ |
350 ClientAuthKeyring(kc), | 337 ClientAuthKeyring(kc), |
351 }, | 338 }, |
352 Crypto: CryptoConfig{ | 339 Crypto: CryptoConfig{ |
353 Ciphers: []string{"aes128-cbc"}, // not currently suppor
ted | 340 Ciphers: []string{"aes128-cbc"}, // not currently suppor
ted |
354 }, | 341 }, |
355 } | 342 } |
356 c, err := Dial("tcp", newMockAuthServer(t), config) | 343 c, err := Dial("tcp", newMockAuthServer(t), config) |
357 if err == nil { | 344 if err == nil { |
358 t.Errorf("expected no ciphers in common") | 345 t.Errorf("expected no ciphers in common") |
359 c.Close() | 346 c.Close() |
360 } | 347 } |
361 } | 348 } |
362 | 349 |
363 func TestClientUnsupportedKex(t *testing.T) { | 350 func TestClientUnsupportedKex(t *testing.T) { |
364 kc := new(keychain) | 351 kc := new(keychain) |
365 kc.keys = append(kc.keys, rsakey) | |
366 config := &ClientConfig{ | 352 config := &ClientConfig{ |
367 User: "testuser", | 353 User: "testuser", |
368 Auth: []ClientAuth{ | 354 Auth: []ClientAuth{ |
369 ClientAuthKeyring(kc), | 355 ClientAuthKeyring(kc), |
370 }, | 356 }, |
371 Crypto: CryptoConfig{ | 357 Crypto: CryptoConfig{ |
372 KeyExchanges: []string{"diffie-hellman-group-exchange-sh
a256"}, // not currently supported | 358 KeyExchanges: []string{"diffie-hellman-group-exchange-sh
a256"}, // not currently supported |
373 }, | 359 }, |
374 } | 360 } |
375 c, err := Dial("tcp", newMockAuthServer(t), config) | 361 c, err := Dial("tcp", newMockAuthServer(t), config) |
376 if err == nil || !strings.Contains(err.Error(), "no common algorithms")
{ | 362 if err == nil || !strings.Contains(err.Error(), "no common algorithms")
{ |
377 t.Errorf("got %v, expected 'no common algorithms'", err) | 363 t.Errorf("got %v, expected 'no common algorithms'", err) |
378 c.Close() | 364 c.Close() |
379 } | 365 } |
380 } | 366 } |
OLD | NEW |