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/ecdsa" | |
11 "crypto/elliptic" | |
12 "crypto/rand" | 9 "crypto/rand" |
13 "encoding/binary" | 10 "encoding/binary" |
14 "errors" | 11 "errors" |
| 12 "fmt" |
15 "io" | 13 "io" |
16 "math/big" | |
17 "net" | 14 "net" |
18 "sync" | 15 "sync" |
19 | 16 |
20 _ "crypto/sha1" | 17 _ "crypto/sha1" |
21 ) | 18 ) |
22 | 19 |
23 type ServerConfig struct { | 20 type ServerConfig struct { |
24 hostKeys []Signer | 21 hostKeys []Signer |
25 | 22 |
26 // Rand provides the source of entropy for key exchange. If Rand is | 23 // Rand provides the source of entropy for key exchange. If Rand is |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 // Server returns a new SSH server connection | 130 // Server returns a new SSH server connection |
134 // using c as the underlying transport. | 131 // using c as the underlying transport. |
135 func Server(c net.Conn, config *ServerConfig) *ServerConn { | 132 func Server(c net.Conn, config *ServerConfig) *ServerConn { |
136 return &ServerConn{ | 133 return &ServerConn{ |
137 transport: newTransport(c, config.rand()), | 134 transport: newTransport(c, config.rand()), |
138 channels: make(map[uint32]*serverChan), | 135 channels: make(map[uint32]*serverChan), |
139 config: config, | 136 config: config, |
140 } | 137 } |
141 } | 138 } |
142 | 139 |
143 // kexECDH performs Elliptic Curve Diffie-Hellman key agreement on a | |
144 // ServerConnection, as documented in RFC 5656, section 4. | |
145 func (s *ServerConn) kexECDH(curve elliptic.Curve, magics *handshakeMagics, priv
Signer) (result *kexResult, err error) { | |
146 packet, err := s.readPacket() | |
147 if err != nil { | |
148 return | |
149 } | |
150 | |
151 var kexECDHInit kexECDHInitMsg | |
152 if err = unmarshal(&kexECDHInit, packet, msgKexECDHInit); err != nil { | |
153 return | |
154 } | |
155 | |
156 clientX, clientY := elliptic.Unmarshal(curve, kexECDHInit.ClientPubKey) | |
157 if clientX == nil { | |
158 return nil, errors.New("ssh: elliptic.Unmarshal failure") | |
159 } | |
160 | |
161 if !validateECPublicKey(curve, clientX, clientY) { | |
162 return nil, errors.New("ssh: not a valid EC public key") | |
163 } | |
164 | |
165 // We could cache this key across multiple users/multiple | |
166 // connection attempts, but the benefit is small. OpenSSH | |
167 // generates a new key for each incoming connection. | |
168 ephKey, err := ecdsa.GenerateKey(curve, s.config.rand()) | |
169 if err != nil { | |
170 return nil, err | |
171 } | |
172 | |
173 hostKeyBytes := MarshalPublicKey(priv.PublicKey()) | |
174 | |
175 serializedEphKey := elliptic.Marshal(curve, ephKey.PublicKey.X, ephKey.P
ublicKey.Y) | |
176 | |
177 // generate shared secret | |
178 secret, _ := curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) | |
179 | |
180 hashFunc := ecHash(curve) | |
181 h := hashFunc.New() | |
182 writeString(h, magics.clientVersion) | |
183 writeString(h, magics.serverVersion) | |
184 writeString(h, magics.clientKexInit) | |
185 writeString(h, magics.serverKexInit) | |
186 writeString(h, hostKeyBytes) | |
187 writeString(h, kexECDHInit.ClientPubKey) | |
188 writeString(h, serializedEphKey) | |
189 | |
190 K := make([]byte, intLength(secret)) | |
191 marshalInt(K, secret) | |
192 h.Write(K) | |
193 | |
194 H := h.Sum(nil) | |
195 | |
196 // H is already a hash, but the hostkey signing will apply its | |
197 // own key specific hash algorithm. | |
198 sig, err := signAndMarshal(priv, s.config.rand(), H) | |
199 if err != nil { | |
200 return nil, err | |
201 } | |
202 | |
203 reply := kexECDHReplyMsg{ | |
204 EphemeralPubKey: serializedEphKey, | |
205 HostKey: hostKeyBytes, | |
206 Signature: sig, | |
207 } | |
208 | |
209 serialized := marshal(msgKexECDHReply, reply) | |
210 if err := s.writePacket(serialized); err != nil { | |
211 return nil, err | |
212 } | |
213 | |
214 return &kexResult{ | |
215 H: H, | |
216 K: K, | |
217 HostKey: reply.HostKey, | |
218 Hash: hashFunc, | |
219 }, nil | |
220 } | |
221 | |
222 // validateECPublicKey checks that the point is a valid public key for | |
223 // the given curve. See [SEC1], 3.2.2 | |
224 func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { | |
225 if x.Sign() == 0 && y.Sign() == 0 { | |
226 return false | |
227 } | |
228 | |
229 if x.Cmp(curve.Params().P) >= 0 { | |
230 return false | |
231 } | |
232 | |
233 if y.Cmp(curve.Params().P) >= 0 { | |
234 return false | |
235 } | |
236 | |
237 if !curve.IsOnCurve(x, y) { | |
238 return false | |
239 } | |
240 | |
241 // We don't check if N * PubKey == 0, since | |
242 // | |
243 // - the NIST curves have cofactor = 1, so this is implicit. | |
244 // (We don't forsee an implementation that supports non NIST | |
245 // curves) | |
246 // | |
247 // - for ephemeral keys, we don't need to worry about small | |
248 // subgroup attacks. | |
249 return true | |
250 } | |
251 | |
252 // kexDH performs Diffie-Hellman key agreement on a ServerConnection. | |
253 func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handsha
keMagics, priv Signer) (result *kexResult, err error) { | |
254 packet, err := s.readPacket() | |
255 if err != nil { | |
256 return | |
257 } | |
258 var kexDHInit kexDHInitMsg | |
259 if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil { | |
260 return | |
261 } | |
262 | |
263 y, err := rand.Int(s.config.rand(), group.p) | |
264 if err != nil { | |
265 return | |
266 } | |
267 | |
268 Y := new(big.Int).Exp(group.g, y, group.p) | |
269 kInt, err := group.diffieHellman(kexDHInit.X, y) | |
270 if err != nil { | |
271 return nil, err | |
272 } | |
273 | |
274 hostKeyBytes := MarshalPublicKey(priv.PublicKey()) | |
275 | |
276 h := hashFunc.New() | |
277 writeString(h, magics.clientVersion) | |
278 writeString(h, magics.serverVersion) | |
279 writeString(h, magics.clientKexInit) | |
280 writeString(h, magics.serverKexInit) | |
281 writeString(h, hostKeyBytes) | |
282 writeInt(h, kexDHInit.X) | |
283 writeInt(h, Y) | |
284 | |
285 K := make([]byte, intLength(kInt)) | |
286 marshalInt(K, kInt) | |
287 h.Write(K) | |
288 | |
289 H := h.Sum(nil) | |
290 | |
291 // H is already a hash, but the hostkey signing will apply its | |
292 // own key specific hash algorithm. | |
293 sig, err := signAndMarshal(priv, s.config.rand(), H) | |
294 if err != nil { | |
295 return nil, err | |
296 } | |
297 | |
298 kexDHReply := kexDHReplyMsg{ | |
299 HostKey: hostKeyBytes, | |
300 Y: Y, | |
301 Signature: sig, | |
302 } | |
303 packet = marshal(msgKexDHReply, kexDHReply) | |
304 | |
305 err = s.writePacket(packet) | |
306 return &kexResult{ | |
307 H: H, | |
308 K: K, | |
309 HostKey: hostKeyBytes, | |
310 Hash: hashFunc, | |
311 }, nil | |
312 } | |
313 | |
314 // signAndMarshal signs the data with the appropriate algorithm, | 140 // signAndMarshal signs the data with the appropriate algorithm, |
315 // and serializes the result in SSH wire format. | 141 // and serializes the result in SSH wire format. |
316 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { | 142 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { |
317 sig, err := k.Sign(rand, data) | 143 sig, err := k.Sign(rand, data) |
318 if err != nil { | 144 if err != nil { |
319 return nil, err | 145 return nil, err |
320 } | 146 } |
321 | 147 |
322 return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil | 148 return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil |
323 } | 149 } |
324 | 150 |
325 // serverVersion is the fixed identification string that Server will use. | 151 // serverVersion is the fixed identification string that Server will use. |
326 var serverVersion = []byte("SSH-2.0-Go\r\n") | 152 var serverVersion = []byte("SSH-2.0-Go\r\n") |
327 | 153 |
328 // Handshake performs an SSH transport and client authentication on the given Se
rverConn. | 154 // Handshake performs an SSH transport and client authentication on the given Se
rverConn. |
329 func (s *ServerConn) Handshake() (err error) { | 155 func (s *ServerConn) Handshake() (err error) { |
330 if _, err = s.Write(serverVersion); err != nil { | 156 if _, err = s.Write(serverVersion); err != nil { |
331 return | 157 return |
332 } | 158 } |
333 » if err = s.Flush(); err != nil { | 159 » if err := s.Flush(); err != nil { |
334 » » return | 160 » » return err |
335 } | 161 } |
336 | 162 |
337 s.ClientVersion, err = readVersion(s) | 163 s.ClientVersion, err = readVersion(s) |
338 if err != nil { | 164 if err != nil { |
339 return | 165 return |
340 } | 166 } |
341 if err = s.clientInitHandshake(nil, nil); err != nil { | 167 if err = s.clientInitHandshake(nil, nil); err != nil { |
342 return | 168 return |
343 } | 169 } |
344 | 170 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 } | 234 } |
409 } | 235 } |
410 | 236 |
411 var hostKey Signer | 237 var hostKey Signer |
412 for _, k := range s.config.hostKeys { | 238 for _, k := range s.config.hostKeys { |
413 if hostKeyAlgo == k.PublicKey().PublicKeyAlgo() { | 239 if hostKeyAlgo == k.PublicKey().PublicKeyAlgo() { |
414 hostKey = k | 240 hostKey = k |
415 } | 241 } |
416 } | 242 } |
417 | 243 |
418 » var magics handshakeMagics | 244 » kex, ok := kexAlgoMap[kexAlgo] |
419 » magics.serverVersion = serverVersion[:len(serverVersion)-2] | 245 » if !ok { |
420 » magics.clientVersion = s.ClientVersion | 246 » » return fmt.Errorf("ssh: unexpected key exchange algorithm %v", k
exAlgo) |
421 » magics.serverKexInit = marshal(msgKexInit, serverKexInit) | 247 » } |
422 » magics.clientKexInit = clientKexInitPacket | |
423 | 248 |
424 » var result *kexResult | 249 » magics := handshakeMagics{ |
425 » switch kexAlgo { | 250 » » serverVersion: serverVersion[:len(serverVersion)-2], |
426 » case kexAlgoECDH256: | 251 » » clientVersion: s.ClientVersion, |
427 » » result, err = s.kexECDH(elliptic.P256(), &magics, hostKey) | 252 » » serverKexInit: marshal(msgKexInit, serverKexInit), |
428 » case kexAlgoECDH384: | 253 » » clientKexInit: clientKexInitPacket, |
429 » » result, err = s.kexECDH(elliptic.P384(), &magics, hostKey) | |
430 » case kexAlgoECDH521: | |
431 » » result, err = s.kexECDH(elliptic.P521(), &magics, hostKey) | |
432 » case kexAlgoDH14SHA1: | |
433 » » dhGroup14Once.Do(initDHGroup14) | |
434 » » result, err = s.kexDH(dhGroup14, crypto.SHA1, &magics, hostKey) | |
435 » case kexAlgoDH1SHA1: | |
436 » » dhGroup1Once.Do(initDHGroup1) | |
437 » » result, err = s.kexDH(dhGroup1, crypto.SHA1, &magics, hostKey) | |
438 » default: | |
439 » » err = errors.New("ssh: unexpected key exchange algorithm " + kex
Algo) | |
440 } | 254 } |
| 255 result, err := kex.Server(s, s.config.rand(), &magics, hostKey) |
441 if err != nil { | 256 if err != nil { |
442 » » return | 257 » » return err |
443 } | 258 } |
| 259 |
444 // sessionId must only be assigned during initial handshake. | 260 // sessionId must only be assigned during initial handshake. |
445 if s.sessionId == nil { | 261 if s.sessionId == nil { |
446 s.sessionId = result.H | 262 s.sessionId = result.H |
447 } | 263 } |
448 | 264 |
449 var packet []byte | 265 var packet []byte |
450 | 266 |
451 if err = s.writePacket([]byte{msgNewKeys}); err != nil { | 267 if err = s.writePacket([]byte{msgNewKeys}); err != nil { |
452 return | 268 return |
453 } | 269 } |
454 » if err = s.transport.writer.setupKeys(serverKeys, result.K, result.H, s.
sessionId, result.Hash); err != nil { | 270 » if err = s.transport.writer.setupKeys(serverKeys, result.K, result.H, s.
sessionId, kex.Hash()); err != nil { |
455 return | 271 return |
456 } | 272 } |
457 | 273 |
458 if packet, err = s.readPacket(); err != nil { | 274 if packet, err = s.readPacket(); err != nil { |
459 return | 275 return |
460 } | 276 } |
461 if packet[0] != msgNewKeys { | 277 if packet[0] != msgNewKeys { |
462 return UnexpectedMessageError{msgNewKeys, packet[0]} | 278 return UnexpectedMessageError{msgNewKeys, packet[0]} |
463 } | 279 } |
464 » if err = s.transport.reader.setupKeys(clientKeys, result.K, result.H, s.
sessionId, result.Hash); err != nil { | 280 » if err = s.transport.reader.setupKeys(clientKeys, result.K, result.H, s.
sessionId, kex.Hash()); err != nil { |
465 return | 281 return |
466 } | 282 } |
467 | 283 |
468 return | 284 return |
469 } | 285 } |
470 | 286 |
471 func isAcceptableAlgo(algo string) bool { | 287 func isAcceptableAlgo(algo string) bool { |
472 switch algo { | 288 switch algo { |
473 case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoEC
DSA521, | 289 case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoEC
DSA521, |
474 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECD
SA384v01, CertAlgoECDSA521v01: | 290 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECD
SA384v01, CertAlgoECDSA521v01: |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 if err != nil { | 569 if err != nil { |
754 return nil, err | 570 return nil, err |
755 } | 571 } |
756 switch msg := decoded.(type) { | 572 switch msg := decoded.(type) { |
757 case *channelOpenMsg: | 573 case *channelOpenMsg: |
758 if msg.MaxPacketSize < minPacketLength || msg.Ma
xPacketSize > 1<<31 { | 574 if msg.MaxPacketSize < minPacketLength || msg.Ma
xPacketSize > 1<<31 { |
759 return nil, errors.New("ssh: invalid Max
PacketSize from peer") | 575 return nil, errors.New("ssh: invalid Max
PacketSize from peer") |
760 } | 576 } |
761 c := &serverChan{ | 577 c := &serverChan{ |
762 channel: channel{ | 578 channel: channel{ |
763 » » » » » » conn: s, | 579 » » » » » » packetConn: s, |
764 » » » » » » remoteId: msg.PeersId, | 580 » » » » » » remoteId: msg.PeersId, |
765 » » » » » » remoteWin: window{Cond: newCond(
)}, | 581 » » » » » » remoteWin: window{Cond: newCond
()}, |
766 » » » » » » maxPacket: msg.MaxPacketSize, | 582 » » » » » » maxPacket: msg.MaxPacketSize, |
767 }, | 583 }, |
768 chanType: msg.ChanType, | 584 chanType: msg.ChanType, |
769 extraData: msg.TypeSpecificData, | 585 extraData: msg.TypeSpecificData, |
770 myWindow: defaultWindowSize, | 586 myWindow: defaultWindowSize, |
771 serverConn: s, | 587 serverConn: s, |
772 cond: newCond(), | 588 cond: newCond(), |
773 pendingData: make([]byte, defaultWindowS
ize), | 589 pendingData: make([]byte, defaultWindowS
ize), |
774 } | 590 } |
775 c.remoteWin.add(msg.PeersWindow) | 591 c.remoteWin.add(msg.PeersWindow) |
776 s.lock.Lock() | 592 s.lock.Lock() |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { | 693 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { |
878 l, err := net.Listen(network, addr) | 694 l, err := net.Listen(network, addr) |
879 if err != nil { | 695 if err != nil { |
880 return nil, err | 696 return nil, err |
881 } | 697 } |
882 return &Listener{ | 698 return &Listener{ |
883 l, | 699 l, |
884 config, | 700 config, |
885 }, nil | 701 }, nil |
886 } | 702 } |
OLD | NEW |