main
Raw Download raw file
  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}