main
1// Copyright 2013 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
5package ssh
6
7import (
8 "crypto"
9 "crypto/ecdsa"
10 "crypto/elliptic"
11 "crypto/rand"
12 "crypto/subtle"
13 "encoding/binary"
14 "errors"
15 "fmt"
16 "io"
17 "math/big"
18
19 "golang.org/x/crypto/curve25519"
20)
21
22const (
23 kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
24 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
25 kexAlgoDH14SHA256 = "diffie-hellman-group14-sha256"
26 kexAlgoDH16SHA512 = "diffie-hellman-group16-sha512"
27 kexAlgoECDH256 = "ecdh-sha2-nistp256"
28 kexAlgoECDH384 = "ecdh-sha2-nistp384"
29 kexAlgoECDH521 = "ecdh-sha2-nistp521"
30 kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org"
31 kexAlgoCurve25519SHA256 = "curve25519-sha256"
32
33 // For the following kex only the client half contains a production
34 // ready implementation. The server half only consists of a minimal
35 // implementation to satisfy the automated tests.
36 kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
37 kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
38)
39
40// kexResult captures the outcome of a key exchange.
41type kexResult struct {
42 // Session hash. See also RFC 4253, section 8.
43 H []byte
44
45 // Shared secret. See also RFC 4253, section 8.
46 K []byte
47
48 // Host key as hashed into H.
49 HostKey []byte
50
51 // Signature of H.
52 Signature []byte
53
54 // A cryptographic hash function that matches the security
55 // level of the key exchange algorithm. It is used for
56 // calculating H, and for deriving keys from H and K.
57 Hash crypto.Hash
58
59 // The session ID, which is the first H computed. This is used
60 // to derive key material inside the transport.
61 SessionID []byte
62}
63
64// handshakeMagics contains data that is always included in the
65// session hash.
66type handshakeMagics struct {
67 clientVersion, serverVersion []byte
68 clientKexInit, serverKexInit []byte
69}
70
71func (m *handshakeMagics) write(w io.Writer) {
72 writeString(w, m.clientVersion)
73 writeString(w, m.serverVersion)
74 writeString(w, m.clientKexInit)
75 writeString(w, m.serverKexInit)
76}
77
78// kexAlgorithm abstracts different key exchange algorithms.
79type kexAlgorithm interface {
80 // Server runs server-side key agreement, signing the result
81 // with a hostkey. algo is the negotiated algorithm, and may
82 // be a certificate type.
83 Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error)
84
85 // Client runs the client-side key agreement. Caller is
86 // responsible for verifying the host key signature.
87 Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
88}
89
90// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
91type dhGroup struct {
92 g, p, pMinus1 *big.Int
93 hashFunc crypto.Hash
94}
95
96func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
97 if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 {
98 return nil, errors.New("ssh: DH parameter out of bounds")
99 }
100 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
101}
102
103func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
104 var x *big.Int
105 for {
106 var err error
107 if x, err = rand.Int(randSource, group.pMinus1); err != nil {
108 return nil, err
109 }
110 if x.Sign() > 0 {
111 break
112 }
113 }
114
115 X := new(big.Int).Exp(group.g, x, group.p)
116 kexDHInit := kexDHInitMsg{
117 X: X,
118 }
119 if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
120 return nil, err
121 }
122
123 packet, err := c.readPacket()
124 if err != nil {
125 return nil, err
126 }
127
128 var kexDHReply kexDHReplyMsg
129 if err = Unmarshal(packet, &kexDHReply); err != nil {
130 return nil, err
131 }
132
133 ki, err := group.diffieHellman(kexDHReply.Y, x)
134 if err != nil {
135 return nil, err
136 }
137
138 h := group.hashFunc.New()
139 magics.write(h)
140 writeString(h, kexDHReply.HostKey)
141 writeInt(h, X)
142 writeInt(h, kexDHReply.Y)
143 K := make([]byte, intLength(ki))
144 marshalInt(K, ki)
145 h.Write(K)
146
147 return &kexResult{
148 H: h.Sum(nil),
149 K: K,
150 HostKey: kexDHReply.HostKey,
151 Signature: kexDHReply.Signature,
152 Hash: group.hashFunc,
153 }, nil
154}
155
156func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
157 packet, err := c.readPacket()
158 if err != nil {
159 return
160 }
161 var kexDHInit kexDHInitMsg
162 if err = Unmarshal(packet, &kexDHInit); err != nil {
163 return
164 }
165
166 var y *big.Int
167 for {
168 if y, err = rand.Int(randSource, group.pMinus1); err != nil {
169 return
170 }
171 if y.Sign() > 0 {
172 break
173 }
174 }
175
176 Y := new(big.Int).Exp(group.g, y, group.p)
177 ki, err := group.diffieHellman(kexDHInit.X, y)
178 if err != nil {
179 return nil, err
180 }
181
182 hostKeyBytes := priv.PublicKey().Marshal()
183
184 h := group.hashFunc.New()
185 magics.write(h)
186 writeString(h, hostKeyBytes)
187 writeInt(h, kexDHInit.X)
188 writeInt(h, Y)
189
190 K := make([]byte, intLength(ki))
191 marshalInt(K, ki)
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, randSource, H, algo)
199 if err != nil {
200 return nil, err
201 }
202
203 kexDHReply := kexDHReplyMsg{
204 HostKey: hostKeyBytes,
205 Y: Y,
206 Signature: sig,
207 }
208 packet = Marshal(&kexDHReply)
209
210 err = c.writePacket(packet)
211 return &kexResult{
212 H: H,
213 K: K,
214 HostKey: hostKeyBytes,
215 Signature: sig,
216 Hash: group.hashFunc,
217 }, err
218}
219
220// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
221// described in RFC 5656, section 4.
222type ecdh struct {
223 curve elliptic.Curve
224}
225
226func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
227 ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
228 if err != nil {
229 return nil, err
230 }
231
232 kexInit := kexECDHInitMsg{
233 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
234 }
235
236 serialized := Marshal(&kexInit)
237 if err := c.writePacket(serialized); err != nil {
238 return nil, err
239 }
240
241 packet, err := c.readPacket()
242 if err != nil {
243 return nil, err
244 }
245
246 var reply kexECDHReplyMsg
247 if err = Unmarshal(packet, &reply); err != nil {
248 return nil, err
249 }
250
251 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
252 if err != nil {
253 return nil, err
254 }
255
256 // generate shared secret
257 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
258
259 h := ecHash(kex.curve).New()
260 magics.write(h)
261 writeString(h, reply.HostKey)
262 writeString(h, kexInit.ClientPubKey)
263 writeString(h, reply.EphemeralPubKey)
264 K := make([]byte, intLength(secret))
265 marshalInt(K, secret)
266 h.Write(K)
267
268 return &kexResult{
269 H: h.Sum(nil),
270 K: K,
271 HostKey: reply.HostKey,
272 Signature: reply.Signature,
273 Hash: ecHash(kex.curve),
274 }, nil
275}
276
277// unmarshalECKey parses and checks an EC key.
278func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
279 x, y = elliptic.Unmarshal(curve, pubkey)
280 if x == nil {
281 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
282 }
283 if !validateECPublicKey(curve, x, y) {
284 return nil, nil, errors.New("ssh: public key not on curve")
285 }
286 return x, y, nil
287}
288
289// validateECPublicKey checks that the point is a valid public key for
290// the given curve. See [SEC1], 3.2.2
291func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
292 if x.Sign() == 0 && y.Sign() == 0 {
293 return false
294 }
295
296 if x.Cmp(curve.Params().P) >= 0 {
297 return false
298 }
299
300 if y.Cmp(curve.Params().P) >= 0 {
301 return false
302 }
303
304 if !curve.IsOnCurve(x, y) {
305 return false
306 }
307
308 // We don't check if N * PubKey == 0, since
309 //
310 // - the NIST curves have cofactor = 1, so this is implicit.
311 // (We don't foresee an implementation that supports non NIST
312 // curves)
313 //
314 // - for ephemeral keys, we don't need to worry about small
315 // subgroup attacks.
316 return true
317}
318
319func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
320 packet, err := c.readPacket()
321 if err != nil {
322 return nil, err
323 }
324
325 var kexECDHInit kexECDHInitMsg
326 if err = Unmarshal(packet, &kexECDHInit); err != nil {
327 return nil, err
328 }
329
330 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
331 if err != nil {
332 return nil, err
333 }
334
335 // We could cache this key across multiple users/multiple
336 // connection attempts, but the benefit is small. OpenSSH
337 // generates a new key for each incoming connection.
338 ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
339 if err != nil {
340 return nil, err
341 }
342
343 hostKeyBytes := priv.PublicKey().Marshal()
344
345 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
346
347 // generate shared secret
348 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
349
350 h := ecHash(kex.curve).New()
351 magics.write(h)
352 writeString(h, hostKeyBytes)
353 writeString(h, kexECDHInit.ClientPubKey)
354 writeString(h, serializedEphKey)
355
356 K := make([]byte, intLength(secret))
357 marshalInt(K, secret)
358 h.Write(K)
359
360 H := h.Sum(nil)
361
362 // H is already a hash, but the hostkey signing will apply its
363 // own key-specific hash algorithm.
364 sig, err := signAndMarshal(priv, rand, H, algo)
365 if err != nil {
366 return nil, err
367 }
368
369 reply := kexECDHReplyMsg{
370 EphemeralPubKey: serializedEphKey,
371 HostKey: hostKeyBytes,
372 Signature: sig,
373 }
374
375 serialized := Marshal(&reply)
376 if err := c.writePacket(serialized); err != nil {
377 return nil, err
378 }
379
380 return &kexResult{
381 H: H,
382 K: K,
383 HostKey: reply.HostKey,
384 Signature: sig,
385 Hash: ecHash(kex.curve),
386 }, nil
387}
388
389// ecHash returns the hash to match the given elliptic curve, see RFC
390// 5656, section 6.2.1
391func ecHash(curve elliptic.Curve) crypto.Hash {
392 bitSize := curve.Params().BitSize
393 switch {
394 case bitSize <= 256:
395 return crypto.SHA256
396 case bitSize <= 384:
397 return crypto.SHA384
398 }
399 return crypto.SHA512
400}
401
402var kexAlgoMap = map[string]kexAlgorithm{}
403
404func init() {
405 // This is the group called diffie-hellman-group1-sha1 in
406 // RFC 4253 and Oakley Group 2 in RFC 2409.
407 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
408 kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
409 g: new(big.Int).SetInt64(2),
410 p: p,
411 pMinus1: new(big.Int).Sub(p, bigOne),
412 hashFunc: crypto.SHA1,
413 }
414
415 // This are the groups called diffie-hellman-group14-sha1 and
416 // diffie-hellman-group14-sha256 in RFC 4253 and RFC 8268,
417 // and Oakley Group 14 in RFC 3526.
418 p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
419 group14 := &dhGroup{
420 g: new(big.Int).SetInt64(2),
421 p: p,
422 pMinus1: new(big.Int).Sub(p, bigOne),
423 }
424
425 kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
426 g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
427 hashFunc: crypto.SHA1,
428 }
429 kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{
430 g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
431 hashFunc: crypto.SHA256,
432 }
433
434 // This is the group called diffie-hellman-group16-sha512 in RFC
435 // 8268 and Oakley Group 16 in RFC 3526.
436 p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", 16)
437
438 kexAlgoMap[kexAlgoDH16SHA512] = &dhGroup{
439 g: new(big.Int).SetInt64(2),
440 p: p,
441 pMinus1: new(big.Int).Sub(p, bigOne),
442 hashFunc: crypto.SHA512,
443 }
444
445 kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
446 kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
447 kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
448 kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
449 kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{}
450 kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
451 kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
452}
453
454// curve25519sha256 implements the curve25519-sha256 (formerly known as
455// curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731.
456type curve25519sha256 struct{}
457
458type curve25519KeyPair struct {
459 priv [32]byte
460 pub [32]byte
461}
462
463func (kp *curve25519KeyPair) generate(rand io.Reader) error {
464 if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
465 return err
466 }
467 curve25519.ScalarBaseMult(&kp.pub, &kp.priv)
468 return nil
469}
470
471// curve25519Zeros is just an array of 32 zero bytes so that we have something
472// convenient to compare against in order to reject curve25519 points with the
473// wrong order.
474var curve25519Zeros [32]byte
475
476func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
477 var kp curve25519KeyPair
478 if err := kp.generate(rand); err != nil {
479 return nil, err
480 }
481 if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
482 return nil, err
483 }
484
485 packet, err := c.readPacket()
486 if err != nil {
487 return nil, err
488 }
489
490 var reply kexECDHReplyMsg
491 if err = Unmarshal(packet, &reply); err != nil {
492 return nil, err
493 }
494 if len(reply.EphemeralPubKey) != 32 {
495 return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
496 }
497
498 var servPub, secret [32]byte
499 copy(servPub[:], reply.EphemeralPubKey)
500 curve25519.ScalarMult(&secret, &kp.priv, &servPub)
501 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
502 return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
503 }
504
505 h := crypto.SHA256.New()
506 magics.write(h)
507 writeString(h, reply.HostKey)
508 writeString(h, kp.pub[:])
509 writeString(h, reply.EphemeralPubKey)
510
511 ki := new(big.Int).SetBytes(secret[:])
512 K := make([]byte, intLength(ki))
513 marshalInt(K, ki)
514 h.Write(K)
515
516 return &kexResult{
517 H: h.Sum(nil),
518 K: K,
519 HostKey: reply.HostKey,
520 Signature: reply.Signature,
521 Hash: crypto.SHA256,
522 }, nil
523}
524
525func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
526 packet, err := c.readPacket()
527 if err != nil {
528 return
529 }
530 var kexInit kexECDHInitMsg
531 if err = Unmarshal(packet, &kexInit); err != nil {
532 return
533 }
534
535 if len(kexInit.ClientPubKey) != 32 {
536 return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
537 }
538
539 var kp curve25519KeyPair
540 if err := kp.generate(rand); err != nil {
541 return nil, err
542 }
543
544 var clientPub, secret [32]byte
545 copy(clientPub[:], kexInit.ClientPubKey)
546 curve25519.ScalarMult(&secret, &kp.priv, &clientPub)
547 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
548 return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
549 }
550
551 hostKeyBytes := priv.PublicKey().Marshal()
552
553 h := crypto.SHA256.New()
554 magics.write(h)
555 writeString(h, hostKeyBytes)
556 writeString(h, kexInit.ClientPubKey)
557 writeString(h, kp.pub[:])
558
559 ki := new(big.Int).SetBytes(secret[:])
560 K := make([]byte, intLength(ki))
561 marshalInt(K, ki)
562 h.Write(K)
563
564 H := h.Sum(nil)
565
566 sig, err := signAndMarshal(priv, rand, H, algo)
567 if err != nil {
568 return nil, err
569 }
570
571 reply := kexECDHReplyMsg{
572 EphemeralPubKey: kp.pub[:],
573 HostKey: hostKeyBytes,
574 Signature: sig,
575 }
576 if err := c.writePacket(Marshal(&reply)); err != nil {
577 return nil, err
578 }
579 return &kexResult{
580 H: H,
581 K: K,
582 HostKey: hostKeyBytes,
583 Signature: sig,
584 Hash: crypto.SHA256,
585 }, nil
586}
587
588// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
589// diffie-hellman-group-exchange-sha256 key agreement protocols,
590// as described in RFC 4419
591type dhGEXSHA struct {
592 hashFunc crypto.Hash
593}
594
595const (
596 dhGroupExchangeMinimumBits = 2048
597 dhGroupExchangePreferredBits = 2048
598 dhGroupExchangeMaximumBits = 8192
599)
600
601func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
602 // Send GexRequest
603 kexDHGexRequest := kexDHGexRequestMsg{
604 MinBits: dhGroupExchangeMinimumBits,
605 PreferedBits: dhGroupExchangePreferredBits,
606 MaxBits: dhGroupExchangeMaximumBits,
607 }
608 if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
609 return nil, err
610 }
611
612 // Receive GexGroup
613 packet, err := c.readPacket()
614 if err != nil {
615 return nil, err
616 }
617
618 var msg kexDHGexGroupMsg
619 if err = Unmarshal(packet, &msg); err != nil {
620 return nil, err
621 }
622
623 // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
624 if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits {
625 return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen())
626 }
627
628 // Check if g is safe by verifying that 1 < g < p-1
629 pMinusOne := new(big.Int).Sub(msg.P, bigOne)
630 if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 {
631 return nil, fmt.Errorf("ssh: server provided gex g is not safe")
632 }
633
634 // Send GexInit
635 pHalf := new(big.Int).Rsh(msg.P, 1)
636 x, err := rand.Int(randSource, pHalf)
637 if err != nil {
638 return nil, err
639 }
640 X := new(big.Int).Exp(msg.G, x, msg.P)
641 kexDHGexInit := kexDHGexInitMsg{
642 X: X,
643 }
644 if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil {
645 return nil, err
646 }
647
648 // Receive GexReply
649 packet, err = c.readPacket()
650 if err != nil {
651 return nil, err
652 }
653
654 var kexDHGexReply kexDHGexReplyMsg
655 if err = Unmarshal(packet, &kexDHGexReply); err != nil {
656 return nil, err
657 }
658
659 if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 {
660 return nil, errors.New("ssh: DH parameter out of bounds")
661 }
662 kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P)
663
664 // Check if k is safe by verifying that k > 1 and k < p - 1
665 if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 {
666 return nil, fmt.Errorf("ssh: derived k is not safe")
667 }
668
669 h := gex.hashFunc.New()
670 magics.write(h)
671 writeString(h, kexDHGexReply.HostKey)
672 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
673 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
674 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
675 writeInt(h, msg.P)
676 writeInt(h, msg.G)
677 writeInt(h, X)
678 writeInt(h, kexDHGexReply.Y)
679 K := make([]byte, intLength(kInt))
680 marshalInt(K, kInt)
681 h.Write(K)
682
683 return &kexResult{
684 H: h.Sum(nil),
685 K: K,
686 HostKey: kexDHGexReply.HostKey,
687 Signature: kexDHGexReply.Signature,
688 Hash: gex.hashFunc,
689 }, nil
690}
691
692// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
693//
694// This is a minimal implementation to satisfy the automated tests.
695func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
696 // Receive GexRequest
697 packet, err := c.readPacket()
698 if err != nil {
699 return
700 }
701 var kexDHGexRequest kexDHGexRequestMsg
702 if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
703 return
704 }
705
706 // Send GexGroup
707 // This is the group called diffie-hellman-group14-sha1 in RFC
708 // 4253 and Oakley Group 14 in RFC 3526.
709 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
710 g := big.NewInt(2)
711
712 msg := &kexDHGexGroupMsg{
713 P: p,
714 G: g,
715 }
716 if err := c.writePacket(Marshal(msg)); err != nil {
717 return nil, err
718 }
719
720 // Receive GexInit
721 packet, err = c.readPacket()
722 if err != nil {
723 return
724 }
725 var kexDHGexInit kexDHGexInitMsg
726 if err = Unmarshal(packet, &kexDHGexInit); err != nil {
727 return
728 }
729
730 pHalf := new(big.Int).Rsh(p, 1)
731
732 y, err := rand.Int(randSource, pHalf)
733 if err != nil {
734 return
735 }
736 Y := new(big.Int).Exp(g, y, p)
737
738 pMinusOne := new(big.Int).Sub(p, bigOne)
739 if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 {
740 return nil, errors.New("ssh: DH parameter out of bounds")
741 }
742 kInt := new(big.Int).Exp(kexDHGexInit.X, y, p)
743
744 hostKeyBytes := priv.PublicKey().Marshal()
745
746 h := gex.hashFunc.New()
747 magics.write(h)
748 writeString(h, hostKeyBytes)
749 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
750 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
751 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
752 writeInt(h, p)
753 writeInt(h, g)
754 writeInt(h, kexDHGexInit.X)
755 writeInt(h, Y)
756
757 K := make([]byte, intLength(kInt))
758 marshalInt(K, kInt)
759 h.Write(K)
760
761 H := h.Sum(nil)
762
763 // H is already a hash, but the hostkey signing will apply its
764 // own key-specific hash algorithm.
765 sig, err := signAndMarshal(priv, randSource, H, algo)
766 if err != nil {
767 return nil, err
768 }
769
770 kexDHGexReply := kexDHGexReplyMsg{
771 HostKey: hostKeyBytes,
772 Y: Y,
773 Signature: sig,
774 }
775 packet = Marshal(&kexDHGexReply)
776
777 err = c.writePacket(packet)
778
779 return &kexResult{
780 H: H,
781 K: K,
782 HostKey: hostKeyBytes,
783 Signature: sig,
784 Hash: gex.hashFunc,
785 }, err
786}