Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1701)

Side by Side Diff: ssh/server.go

Issue 13352055: code review 13352055: go.crypto/ssh: separate kex algorithms into kexAlgorith... (Closed)
Patch Set: diff -r 3a49c11added https://code.google.com/p/go.crypto Created 10 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ssh/kex_test.go ('k') | ssh/transport.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « ssh/kex_test.go ('k') | ssh/transport.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b