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

Side by Side Diff: ssh/server.go

Issue 13338044: code review 13338044: go.crypto/ssh: introduce PrivateKey method. (Closed)
Patch Set: diff -r c923f02daf74 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/keys_test.go ('k') | ssh/test/keys_test.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" 9 "crypto"
10 "crypto/ecdsa" 10 "crypto/ecdsa"
11 "crypto/elliptic" 11 "crypto/elliptic"
12 "crypto/rand" 12 "crypto/rand"
13 "crypto/rsa"
14 "crypto/x509"
15 "encoding/binary" 13 "encoding/binary"
16 "encoding/pem"
17 "errors" 14 "errors"
18 "io" 15 "io"
19 "math/big" 16 "math/big"
20 "net" 17 "net"
21 "sync" 18 "sync"
22 19
23 _ "crypto/sha1" 20 _ "crypto/sha1"
24 ) 21 )
25 22
26 type ServerConfig struct { 23 type ServerConfig struct {
27 » rsa *rsa.PrivateKey 24 » hostKeys []Signer
28
29 » // rsaSerialized is the serialized form of the public key that
30 » // corresponds to the private key held in the rsa field.
31 » rsaSerialized []byte
32 25
33 // Rand provides the source of entropy for key exchange. If Rand is 26 // Rand provides the source of entropy for key exchange. If Rand is
34 // nil, the cryptographic random reader in package crypto/rand will 27 // nil, the cryptographic random reader in package crypto/rand will
35 // be used. 28 // be used.
36 Rand io.Reader 29 Rand io.Reader
37 30
38 // NoClientAuth is true if clients are allowed to connect without 31 // NoClientAuth is true if clients are allowed to connect without
39 // authenticating. 32 // authenticating.
40 NoClientAuth bool 33 NoClientAuth bool
41 34
(...skipping 20 matching lines...) Expand all
62 Crypto CryptoConfig 55 Crypto CryptoConfig
63 } 56 }
64 57
65 func (c *ServerConfig) rand() io.Reader { 58 func (c *ServerConfig) rand() io.Reader {
66 if c.Rand == nil { 59 if c.Rand == nil {
67 return rand.Reader 60 return rand.Reader
68 } 61 }
69 return c.Rand 62 return c.Rand
70 } 63 }
71 64
65 // AddHostKey adds a private key as a host key. If an existing host
66 // key exists with the same algorithm, it is overwritten.
67 func (s *ServerConfig) AddHostKey(key Signer) {
68 for i, k := range s.hostKeys {
69 if k.PublicKey().PublicKeyAlgo() == key.PublicKey().PublicKeyAlg o() {
70 s.hostKeys[i] = key
71 return
72 }
73 }
74
75 s.hostKeys = append(s.hostKeys, key)
76 }
77
72 // SetRSAPrivateKey sets the private key for a Server. A Server must have a 78 // SetRSAPrivateKey sets the private key for a Server. A Server must have a
73 // private key configured in order to accept connections. The private key must 79 // private key configured in order to accept connections. The private key must
74 // be in the form of a PEM encoded, PKCS#1, RSA private key. The file "id_rsa" 80 // be in the form of a PEM encoded, PKCS#1, RSA private key. The file "id_rsa"
75 // typically contains such a key. 81 // typically contains such a key.
76 func (s *ServerConfig) SetRSAPrivateKey(pemBytes []byte) error { 82 func (s *ServerConfig) SetRSAPrivateKey(pemBytes []byte) error {
77 » block, _ := pem.Decode(pemBytes) 83 » priv, err := ParsePrivateKey(pemBytes)
78 » if block == nil {
79 » » return errors.New("ssh: no key found")
80 » }
81 » rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
82 if err != nil { 84 if err != nil {
83 return err 85 return err
84 } 86 }
85 » s.rsa = rsa 87 » s.AddHostKey(priv)
86 » s.rsaSerialized = MarshalPublicKey(NewRSAPublicKey(&rsa.PublicKey))
87 return nil 88 return nil
88 } 89 }
89 90
90 // cachedPubKey contains the results of querying whether a public key is 91 // cachedPubKey contains the results of querying whether a public key is
91 // acceptable for a user. The cache only applies to a single ServerConn. 92 // acceptable for a user. The cache only applies to a single ServerConn.
92 type cachedPubKey struct { 93 type cachedPubKey struct {
93 user, algo string 94 user, algo string
94 pubKey []byte 95 pubKey []byte
95 result bool 96 result bool
96 } 97 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 func Server(c net.Conn, config *ServerConfig) *ServerConn { 135 func Server(c net.Conn, config *ServerConfig) *ServerConn {
135 return &ServerConn{ 136 return &ServerConn{
136 transport: newTransport(c, config.rand()), 137 transport: newTransport(c, config.rand()),
137 channels: make(map[uint32]*serverChan), 138 channels: make(map[uint32]*serverChan),
138 config: config, 139 config: config,
139 } 140 }
140 } 141 }
141 142
142 // kexECDH performs Elliptic Curve Diffie-Hellman key agreement on a 143 // kexECDH performs Elliptic Curve Diffie-Hellman key agreement on a
143 // ServerConnection, as documented in RFC 5656, section 4. 144 // ServerConnection, as documented in RFC 5656, section 4.
144 func (s *ServerConn) kexECDH(curve elliptic.Curve, magics *handshakeMagics, host KeyAlgo string) (result *kexResult, err error) { 145 func (s *ServerConn) kexECDH(curve elliptic.Curve, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
145 packet, err := s.readPacket() 146 packet, err := s.readPacket()
146 if err != nil { 147 if err != nil {
147 return 148 return
148 } 149 }
149 150
150 var kexECDHInit kexECDHInitMsg 151 var kexECDHInit kexECDHInitMsg
151 if err = unmarshal(&kexECDHInit, packet, msgKexECDHInit); err != nil { 152 if err = unmarshal(&kexECDHInit, packet, msgKexECDHInit); err != nil {
152 return 153 return
153 } 154 }
154 155
155 clientX, clientY := elliptic.Unmarshal(curve, kexECDHInit.ClientPubKey) 156 clientX, clientY := elliptic.Unmarshal(curve, kexECDHInit.ClientPubKey)
156 if clientX == nil { 157 if clientX == nil {
157 return nil, errors.New("ssh: elliptic.Unmarshal failure") 158 return nil, errors.New("ssh: elliptic.Unmarshal failure")
158 } 159 }
159 160
160 if !validateECPublicKey(curve, clientX, clientY) { 161 if !validateECPublicKey(curve, clientX, clientY) {
161 return nil, errors.New("ssh: not a valid EC public key") 162 return nil, errors.New("ssh: not a valid EC public key")
162 } 163 }
163 164
164 // We could cache this key across multiple users/multiple 165 // We could cache this key across multiple users/multiple
165 // connection attempts, but the benefit is small. OpenSSH 166 // connection attempts, but the benefit is small. OpenSSH
166 // generates a new key for each incoming connection. 167 // generates a new key for each incoming connection.
167 ephKey, err := ecdsa.GenerateKey(curve, s.config.rand()) 168 ephKey, err := ecdsa.GenerateKey(curve, s.config.rand())
168 if err != nil { 169 if err != nil {
169 return nil, err 170 return nil, err
170 } 171 }
171 172
172 » hostKeyBytes := s.config.rsaSerialized 173 » hostKeyBytes := MarshalPublicKey(priv.PublicKey())
173 174
174 serializedEphKey := elliptic.Marshal(curve, ephKey.PublicKey.X, ephKey.P ublicKey.Y) 175 serializedEphKey := elliptic.Marshal(curve, ephKey.PublicKey.X, ephKey.P ublicKey.Y)
175 176
176 // generate shared secret 177 // generate shared secret
177 secret, _ := curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) 178 secret, _ := curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
178 179
179 hashFunc := ecHash(curve) 180 hashFunc := ecHash(curve)
180 h := hashFunc.New() 181 h := hashFunc.New()
181 writeString(h, magics.clientVersion) 182 writeString(h, magics.clientVersion)
182 writeString(h, magics.serverVersion) 183 writeString(h, magics.serverVersion)
183 writeString(h, magics.clientKexInit) 184 writeString(h, magics.clientKexInit)
184 writeString(h, magics.serverKexInit) 185 writeString(h, magics.serverKexInit)
185 writeString(h, hostKeyBytes) 186 writeString(h, hostKeyBytes)
186 writeString(h, kexECDHInit.ClientPubKey) 187 writeString(h, kexECDHInit.ClientPubKey)
187 writeString(h, serializedEphKey) 188 writeString(h, serializedEphKey)
188 189
189 K := make([]byte, intLength(secret)) 190 K := make([]byte, intLength(secret))
190 marshalInt(K, secret) 191 marshalInt(K, secret)
191 h.Write(K) 192 h.Write(K)
192 193
193 H := h.Sum(nil) 194 H := h.Sum(nil)
194 195
195 » sig, err := s.serializedHostKeySignature(hostKeyAlgo, H) 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)
196 if err != nil { 199 if err != nil {
197 return nil, err 200 return nil, err
198 } 201 }
199 202
200 reply := kexECDHReplyMsg{ 203 reply := kexECDHReplyMsg{
201 EphemeralPubKey: serializedEphKey, 204 EphemeralPubKey: serializedEphKey,
202 HostKey: hostKeyBytes, 205 HostKey: hostKeyBytes,
203 Signature: sig, 206 Signature: sig,
204 } 207 }
205 208
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 // - the NIST curves have cofactor = 1, so this is implicit. 243 // - the NIST curves have cofactor = 1, so this is implicit.
241 // (We don't forsee an implementation that supports non NIST 244 // (We don't forsee an implementation that supports non NIST
242 // curves) 245 // curves)
243 // 246 //
244 // - for ephemeral keys, we don't need to worry about small 247 // - for ephemeral keys, we don't need to worry about small
245 // subgroup attacks. 248 // subgroup attacks.
246 return true 249 return true
247 } 250 }
248 251
249 // kexDH performs Diffie-Hellman key agreement on a ServerConnection. 252 // kexDH performs Diffie-Hellman key agreement on a ServerConnection.
250 func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handsha keMagics, hostKeyAlgo string) (result *kexResult, err error) { 253 func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handsha keMagics, priv Signer) (result *kexResult, err error) {
251 packet, err := s.readPacket() 254 packet, err := s.readPacket()
252 if err != nil { 255 if err != nil {
253 return 256 return
254 } 257 }
255 var kexDHInit kexDHInitMsg 258 var kexDHInit kexDHInitMsg
256 if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil { 259 if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil {
257 return 260 return
258 } 261 }
259 262
260 y, err := rand.Int(s.config.rand(), group.p) 263 y, err := rand.Int(s.config.rand(), group.p)
261 if err != nil { 264 if err != nil {
262 return 265 return
263 } 266 }
264 267
265 Y := new(big.Int).Exp(group.g, y, group.p) 268 Y := new(big.Int).Exp(group.g, y, group.p)
266 kInt, err := group.diffieHellman(kexDHInit.X, y) 269 kInt, err := group.diffieHellman(kexDHInit.X, y)
267 if err != nil { 270 if err != nil {
268 return nil, err 271 return nil, err
269 } 272 }
270 273
271 » hostKeyBytes := s.config.rsaSerialized 274 » hostKeyBytes := MarshalPublicKey(priv.PublicKey())
272 275
273 h := hashFunc.New() 276 h := hashFunc.New()
274 writeString(h, magics.clientVersion) 277 writeString(h, magics.clientVersion)
275 writeString(h, magics.serverVersion) 278 writeString(h, magics.serverVersion)
276 writeString(h, magics.clientKexInit) 279 writeString(h, magics.clientKexInit)
277 writeString(h, magics.serverKexInit) 280 writeString(h, magics.serverKexInit)
278 writeString(h, hostKeyBytes) 281 writeString(h, hostKeyBytes)
279 writeInt(h, kexDHInit.X) 282 writeInt(h, kexDHInit.X)
280 writeInt(h, Y) 283 writeInt(h, Y)
281 284
282 K := make([]byte, intLength(kInt)) 285 K := make([]byte, intLength(kInt))
283 marshalInt(K, kInt) 286 marshalInt(K, kInt)
284 h.Write(K) 287 h.Write(K)
285 288
286 H := h.Sum(nil) 289 H := h.Sum(nil)
287 290
288 » sig, err := s.serializedHostKeySignature(hostKeyAlgo, H) 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)
289 if err != nil { 294 if err != nil {
290 return nil, err 295 return nil, err
291 } 296 }
292 297
293 kexDHReply := kexDHReplyMsg{ 298 kexDHReply := kexDHReplyMsg{
294 HostKey: hostKeyBytes, 299 HostKey: hostKeyBytes,
295 Y: Y, 300 Y: Y,
296 Signature: sig, 301 Signature: sig,
297 } 302 }
298 packet = marshal(msgKexDHReply, kexDHReply) 303 packet = marshal(msgKexDHReply, kexDHReply)
299 304
300 err = s.writePacket(packet) 305 err = s.writePacket(packet)
301 return &kexResult{ 306 return &kexResult{
302 H: H, 307 H: H,
303 K: K, 308 K: K,
304 HostKey: hostKeyBytes, 309 HostKey: hostKeyBytes,
305 Hash: hashFunc, 310 Hash: hashFunc,
306 }, nil 311 }, nil
307 } 312 }
308 313
309 // serializedHostKeySignature signs the hashed data, and serializes 314 // signAndMarshal signs the data with the appropriate algorithm,
310 // the signature according to SSH conventions. 315 // and serializes the result in SSH wire format.
311 func (s *ServerConn) serializedHostKeySignature(hostKeyAlgo string, hashed []byt e) ([]byte, error) { 316 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
312 » var sig []byte 317 » sig, err := k.Sign(rand, data)
313 » switch hostKeyAlgo { 318 » if err != nil {
314 » case hostAlgoRSA: 319 » » return nil, err
315 » » hashFunc := crypto.SHA1
316 » » hh := hashFunc.New()
317 » » hh.Write(hashed)
318 » » var err error
319 » » sig, err = rsa.SignPKCS1v15(s.config.rand(), s.config.rsa, hashF unc, hh.Sum(nil))
320 » » if err != nil {
321 » » » return nil, err
322 » » }
323 » default:
324 » » return nil, errors.New("ssh: internal error")
325 } 320 }
326 321
327 » return serializeSignature(hostKeyAlgo, sig), nil 322 » return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil
328 } 323 }
329 324
330 // serverVersion is the fixed identification string that Server will use. 325 // serverVersion is the fixed identification string that Server will use.
331 var serverVersion = []byte("SSH-2.0-Go\r\n") 326 var serverVersion = []byte("SSH-2.0-Go\r\n")
332 327
333 // Handshake performs an SSH transport and client authentication on the given Se rverConn. 328 // Handshake performs an SSH transport and client authentication on the given Se rverConn.
334 func (s *ServerConn) Handshake() (err error) { 329 func (s *ServerConn) Handshake() (err error) {
335 if _, err = s.Write(serverVersion); err != nil { 330 if _, err = s.Write(serverVersion); err != nil {
336 return 331 return
337 } 332 }
(...skipping 29 matching lines...) Expand all
367 362
368 if err = s.authenticate(s.sessionId); err != nil { 363 if err = s.authenticate(s.sessionId); err != nil {
369 return 364 return
370 } 365 }
371 return 366 return
372 } 367 }
373 368
374 func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexIni tPacket []byte) (err error) { 369 func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexIni tPacket []byte) (err error) {
375 serverKexInit := kexInitMsg{ 370 serverKexInit := kexInitMsg{
376 KexAlgos: s.config.Crypto.kexes(), 371 KexAlgos: s.config.Crypto.kexes(),
377 ServerHostKeyAlgos: supportedHostKeyAlgos,
378 CiphersClientServer: s.config.Crypto.ciphers(), 372 CiphersClientServer: s.config.Crypto.ciphers(),
379 CiphersServerClient: s.config.Crypto.ciphers(), 373 CiphersServerClient: s.config.Crypto.ciphers(),
380 MACsClientServer: s.config.Crypto.macs(), 374 MACsClientServer: s.config.Crypto.macs(),
381 MACsServerClient: s.config.Crypto.macs(), 375 MACsServerClient: s.config.Crypto.macs(),
382 CompressionClientServer: supportedCompressions, 376 CompressionClientServer: supportedCompressions,
383 CompressionServerClient: supportedCompressions, 377 CompressionServerClient: supportedCompressions,
384 } 378 }
379 for _, k := range s.config.hostKeys {
380 serverKexInit.ServerHostKeyAlgos = append(
381 serverKexInit.ServerHostKeyAlgos, k.PublicKey().PublicKe yAlgo())
382 }
383
385 serverKexInitPacket := marshal(msgKexInit, serverKexInit) 384 serverKexInitPacket := marshal(msgKexInit, serverKexInit)
386
387 if err = s.writePacket(serverKexInitPacket); err != nil { 385 if err = s.writePacket(serverKexInitPacket); err != nil {
388 return 386 return
389 } 387 }
390 388
391 if clientKexInitPacket == nil { 389 if clientKexInitPacket == nil {
392 clientKexInit = new(kexInitMsg) 390 clientKexInit = new(kexInitMsg)
393 if clientKexInitPacket, err = s.readPacket(); err != nil { 391 if clientKexInitPacket, err = s.readPacket(); err != nil {
394 return 392 return
395 } 393 }
396 if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexIni t); err != nil { 394 if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexIni t); err != nil {
397 return 395 return
398 } 396 }
399 } 397 }
400 398
401 kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(s.transport, clientKexI nit, &serverKexInit) 399 kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(s.transport, clientKexI nit, &serverKexInit)
402 if !ok { 400 if !ok {
403 return errors.New("ssh: no common algorithms") 401 return errors.New("ssh: no common algorithms")
404 } 402 }
405 if clientKexInit.FirstKexFollows && kexAlgo != clientKexInit.KexAlgos[0] { 403 if clientKexInit.FirstKexFollows && kexAlgo != clientKexInit.KexAlgos[0] {
406 // The client sent a Kex message for the wrong algorithm, 404 // The client sent a Kex message for the wrong algorithm,
407 // which we have to ignore. 405 // which we have to ignore.
408 if _, err = s.readPacket(); err != nil { 406 if _, err = s.readPacket(); err != nil {
409 return 407 return
410 } 408 }
411 } 409 }
412 410
411 var hostKey Signer
412 for _, k := range s.config.hostKeys {
413 if hostKeyAlgo == k.PublicKey().PublicKeyAlgo() {
414 hostKey = k
415 }
416 }
417
413 var magics handshakeMagics 418 var magics handshakeMagics
414 magics.serverVersion = serverVersion[:len(serverVersion)-2] 419 magics.serverVersion = serverVersion[:len(serverVersion)-2]
415 magics.clientVersion = s.ClientVersion 420 magics.clientVersion = s.ClientVersion
416 magics.serverKexInit = marshal(msgKexInit, serverKexInit) 421 magics.serverKexInit = marshal(msgKexInit, serverKexInit)
417 magics.clientKexInit = clientKexInitPacket 422 magics.clientKexInit = clientKexInitPacket
418 423
419 var result *kexResult 424 var result *kexResult
420 switch kexAlgo { 425 switch kexAlgo {
421 case kexAlgoECDH256: 426 case kexAlgoECDH256:
422 » » result, err = s.kexECDH(elliptic.P256(), &magics, hostKeyAlgo) 427 » » result, err = s.kexECDH(elliptic.P256(), &magics, hostKey)
423 case kexAlgoECDH384: 428 case kexAlgoECDH384:
424 » » result, err = s.kexECDH(elliptic.P384(), &magics, hostKeyAlgo) 429 » » result, err = s.kexECDH(elliptic.P384(), &magics, hostKey)
425 case kexAlgoECDH521: 430 case kexAlgoECDH521:
426 » » result, err = s.kexECDH(elliptic.P521(), &magics, hostKeyAlgo) 431 » » result, err = s.kexECDH(elliptic.P521(), &magics, hostKey)
427 case kexAlgoDH14SHA1: 432 case kexAlgoDH14SHA1:
428 dhGroup14Once.Do(initDHGroup14) 433 dhGroup14Once.Do(initDHGroup14)
429 » » result, err = s.kexDH(dhGroup14, crypto.SHA1, &magics, hostKeyAl go) 434 » » result, err = s.kexDH(dhGroup14, crypto.SHA1, &magics, hostKey)
430 case kexAlgoDH1SHA1: 435 case kexAlgoDH1SHA1:
431 dhGroup1Once.Do(initDHGroup1) 436 dhGroup1Once.Do(initDHGroup1)
432 » » result, err = s.kexDH(dhGroup1, crypto.SHA1, &magics, hostKeyAlg o) 437 » » result, err = s.kexDH(dhGroup1, crypto.SHA1, &magics, hostKey)
433 default: 438 default:
434 err = errors.New("ssh: unexpected key exchange algorithm " + kex Algo) 439 err = errors.New("ssh: unexpected key exchange algorithm " + kex Algo)
435 } 440 }
436 if err != nil { 441 if err != nil {
437 return 442 return
438 } 443 }
439 // sessionId must only be assigned during initial handshake. 444 // sessionId must only be assigned during initial handshake.
440 if s.sessionId == nil { 445 if s.sessionId == nil {
441 s.sessionId = result.H 446 s.sessionId = result.H
442 } 447 }
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after
872 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { 877 func Listen(network, addr string, config *ServerConfig) (*Listener, error) {
873 l, err := net.Listen(network, addr) 878 l, err := net.Listen(network, addr)
874 if err != nil { 879 if err != nil {
875 return nil, err 880 return nil, err
876 } 881 }
877 return &Listener{ 882 return &Listener{
878 l, 883 l,
879 config, 884 config,
880 }, nil 885 }, nil
881 } 886 }
OLDNEW
« no previous file with comments | « ssh/keys_test.go ('k') | ssh/test/keys_test.go » ('j') | no next file with comments »

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