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