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}