mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 05:22:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			783 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			783 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2013 The Go Authors. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by a BSD-style
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package ssh
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"crypto"
							 | 
						||
| 
								 | 
							
									"crypto/ecdsa"
							 | 
						||
| 
								 | 
							
									"crypto/elliptic"
							 | 
						||
| 
								 | 
							
									"crypto/rand"
							 | 
						||
| 
								 | 
							
									"crypto/subtle"
							 | 
						||
| 
								 | 
							
									"encoding/binary"
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"io"
							 | 
						||
| 
								 | 
							
									"math/big"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"golang.org/x/crypto/curve25519"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									kexAlgoDH1SHA1          = "diffie-hellman-group1-sha1"
							 | 
						||
| 
								 | 
							
									kexAlgoDH14SHA1         = "diffie-hellman-group14-sha1"
							 | 
						||
| 
								 | 
							
									kexAlgoECDH256          = "ecdh-sha2-nistp256"
							 | 
						||
| 
								 | 
							
									kexAlgoECDH384          = "ecdh-sha2-nistp384"
							 | 
						||
| 
								 | 
							
									kexAlgoECDH521          = "ecdh-sha2-nistp521"
							 | 
						||
| 
								 | 
							
									kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// For the following kex only the client half contains a production
							 | 
						||
| 
								 | 
							
									// ready implementation. The server half only consists of a minimal
							 | 
						||
| 
								 | 
							
									// implementation to satisfy the automated tests.
							 | 
						||
| 
								 | 
							
									kexAlgoDHGEXSHA1   = "diffie-hellman-group-exchange-sha1"
							 | 
						||
| 
								 | 
							
									kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// kexResult captures the outcome of a key exchange.
							 | 
						||
| 
								 | 
							
								type kexResult struct {
							 | 
						||
| 
								 | 
							
									// Session hash. See also RFC 4253, section 8.
							 | 
						||
| 
								 | 
							
									H []byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Shared secret. See also RFC 4253, section 8.
							 | 
						||
| 
								 | 
							
									K []byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Host key as hashed into H.
							 | 
						||
| 
								 | 
							
									HostKey []byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Signature of H.
							 | 
						||
| 
								 | 
							
									Signature []byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// A cryptographic hash function that matches the security
							 | 
						||
| 
								 | 
							
									// level of the key exchange algorithm. It is used for
							 | 
						||
| 
								 | 
							
									// calculating H, and for deriving keys from H and K.
							 | 
						||
| 
								 | 
							
									Hash crypto.Hash
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// The session ID, which is the first H computed. This is used
							 | 
						||
| 
								 | 
							
									// to derive key material inside the transport.
							 | 
						||
| 
								 | 
							
									SessionID []byte
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// handshakeMagics contains data that is always included in the
							 | 
						||
| 
								 | 
							
								// session hash.
							 | 
						||
| 
								 | 
							
								type handshakeMagics struct {
							 | 
						||
| 
								 | 
							
									clientVersion, serverVersion []byte
							 | 
						||
| 
								 | 
							
									clientKexInit, serverKexInit []byte
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (m *handshakeMagics) write(w io.Writer) {
							 | 
						||
| 
								 | 
							
									writeString(w, m.clientVersion)
							 | 
						||
| 
								 | 
							
									writeString(w, m.serverVersion)
							 | 
						||
| 
								 | 
							
									writeString(w, m.clientKexInit)
							 | 
						||
| 
								 | 
							
									writeString(w, m.serverKexInit)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// kexAlgorithm abstracts different key exchange algorithms.
							 | 
						||
| 
								 | 
							
								type kexAlgorithm interface {
							 | 
						||
| 
								 | 
							
									// Server runs server-side key agreement, signing the result
							 | 
						||
| 
								 | 
							
									// with a hostkey.
							 | 
						||
| 
								 | 
							
									Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Client runs the client-side key agreement. Caller is
							 | 
						||
| 
								 | 
							
									// responsible for verifying the host key signature.
							 | 
						||
| 
								 | 
							
									Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
							 | 
						||
| 
								 | 
							
								type dhGroup struct {
							 | 
						||
| 
								 | 
							
									g, p, pMinus1 *big.Int
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
							 | 
						||
| 
								 | 
							
									if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 {
							 | 
						||
| 
								 | 
							
										return nil, errors.New("ssh: DH parameter out of bounds")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
							 | 
						||
| 
								 | 
							
									hashFunc := crypto.SHA1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var x *big.Int
							 | 
						||
| 
								 | 
							
									for {
							 | 
						||
| 
								 | 
							
										var err error
							 | 
						||
| 
								 | 
							
										if x, err = rand.Int(randSource, group.pMinus1); err != nil {
							 | 
						||
| 
								 | 
							
											return nil, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if x.Sign() > 0 {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									X := new(big.Int).Exp(group.g, x, group.p)
							 | 
						||
| 
								 | 
							
									kexDHInit := kexDHInitMsg{
							 | 
						||
| 
								 | 
							
										X: X,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var kexDHReply kexDHReplyMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexDHReply); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ki, err := group.diffieHellman(kexDHReply.Y, x)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := hashFunc.New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, kexDHReply.HostKey)
							 | 
						||
| 
								 | 
							
									writeInt(h, X)
							 | 
						||
| 
								 | 
							
									writeInt(h, kexDHReply.Y)
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(ki))
							 | 
						||
| 
								 | 
							
									marshalInt(K, ki)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         h.Sum(nil),
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   kexDHReply.HostKey,
							 | 
						||
| 
								 | 
							
										Signature: kexDHReply.Signature,
							 | 
						||
| 
								 | 
							
										Hash:      crypto.SHA1,
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
							 | 
						||
| 
								 | 
							
									hashFunc := crypto.SHA1
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var kexDHInit kexDHInitMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexDHInit); err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var y *big.Int
							 | 
						||
| 
								 | 
							
									for {
							 | 
						||
| 
								 | 
							
										if y, err = rand.Int(randSource, group.pMinus1); err != nil {
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if y.Sign() > 0 {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									Y := new(big.Int).Exp(group.g, y, group.p)
							 | 
						||
| 
								 | 
							
									ki, err := group.diffieHellman(kexDHInit.X, y)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									hostKeyBytes := priv.PublicKey().Marshal()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := hashFunc.New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, hostKeyBytes)
							 | 
						||
| 
								 | 
							
									writeInt(h, kexDHInit.X)
							 | 
						||
| 
								 | 
							
									writeInt(h, Y)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(ki))
							 | 
						||
| 
								 | 
							
									marshalInt(K, ki)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									H := h.Sum(nil)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// H is already a hash, but the hostkey signing will apply its
							 | 
						||
| 
								 | 
							
									// own key-specific hash algorithm.
							 | 
						||
| 
								 | 
							
									sig, err := signAndMarshal(priv, randSource, H)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kexDHReply := kexDHReplyMsg{
							 | 
						||
| 
								 | 
							
										HostKey:   hostKeyBytes,
							 | 
						||
| 
								 | 
							
										Y:         Y,
							 | 
						||
| 
								 | 
							
										Signature: sig,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									packet = Marshal(&kexDHReply)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = c.writePacket(packet)
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         H,
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   hostKeyBytes,
							 | 
						||
| 
								 | 
							
										Signature: sig,
							 | 
						||
| 
								 | 
							
										Hash:      crypto.SHA1,
							 | 
						||
| 
								 | 
							
									}, err
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
							 | 
						||
| 
								 | 
							
								// described in RFC 5656, section 4.
							 | 
						||
| 
								 | 
							
								type ecdh struct {
							 | 
						||
| 
								 | 
							
									curve elliptic.Curve
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
							 | 
						||
| 
								 | 
							
									ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kexInit := kexECDHInitMsg{
							 | 
						||
| 
								 | 
							
										ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									serialized := Marshal(&kexInit)
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(serialized); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var reply kexECDHReplyMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &reply); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// generate shared secret
							 | 
						||
| 
								 | 
							
									secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := ecHash(kex.curve).New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, reply.HostKey)
							 | 
						||
| 
								 | 
							
									writeString(h, kexInit.ClientPubKey)
							 | 
						||
| 
								 | 
							
									writeString(h, reply.EphemeralPubKey)
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(secret))
							 | 
						||
| 
								 | 
							
									marshalInt(K, secret)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         h.Sum(nil),
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   reply.HostKey,
							 | 
						||
| 
								 | 
							
										Signature: reply.Signature,
							 | 
						||
| 
								 | 
							
										Hash:      ecHash(kex.curve),
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// unmarshalECKey parses and checks an EC key.
							 | 
						||
| 
								 | 
							
								func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
							 | 
						||
| 
								 | 
							
									x, y = elliptic.Unmarshal(curve, pubkey)
							 | 
						||
| 
								 | 
							
									if x == nil {
							 | 
						||
| 
								 | 
							
										return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if !validateECPublicKey(curve, x, y) {
							 | 
						||
| 
								 | 
							
										return nil, nil, errors.New("ssh: public key not on curve")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return x, y, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// validateECPublicKey checks that the point is a valid public key for
							 | 
						||
| 
								 | 
							
								// the given curve. See [SEC1], 3.2.2
							 | 
						||
| 
								 | 
							
								func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
							 | 
						||
| 
								 | 
							
									if x.Sign() == 0 && y.Sign() == 0 {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if x.Cmp(curve.Params().P) >= 0 {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if y.Cmp(curve.Params().P) >= 0 {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if !curve.IsOnCurve(x, y) {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// We don't check if N * PubKey == 0, since
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// - the NIST curves have cofactor = 1, so this is implicit.
							 | 
						||
| 
								 | 
							
									// (We don't foresee an implementation that supports non NIST
							 | 
						||
| 
								 | 
							
									// curves)
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// - for ephemeral keys, we don't need to worry about small
							 | 
						||
| 
								 | 
							
									// subgroup attacks.
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var kexECDHInit kexECDHInitMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexECDHInit); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// We could cache this key across multiple users/multiple
							 | 
						||
| 
								 | 
							
									// connection attempts, but the benefit is small. OpenSSH
							 | 
						||
| 
								 | 
							
									// generates a new key for each incoming connection.
							 | 
						||
| 
								 | 
							
									ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									hostKeyBytes := priv.PublicKey().Marshal()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// generate shared secret
							 | 
						||
| 
								 | 
							
									secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := ecHash(kex.curve).New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, hostKeyBytes)
							 | 
						||
| 
								 | 
							
									writeString(h, kexECDHInit.ClientPubKey)
							 | 
						||
| 
								 | 
							
									writeString(h, serializedEphKey)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(secret))
							 | 
						||
| 
								 | 
							
									marshalInt(K, secret)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									H := h.Sum(nil)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// H is already a hash, but the hostkey signing will apply its
							 | 
						||
| 
								 | 
							
									// own key-specific hash algorithm.
							 | 
						||
| 
								 | 
							
									sig, err := signAndMarshal(priv, rand, H)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									reply := kexECDHReplyMsg{
							 | 
						||
| 
								 | 
							
										EphemeralPubKey: serializedEphKey,
							 | 
						||
| 
								 | 
							
										HostKey:         hostKeyBytes,
							 | 
						||
| 
								 | 
							
										Signature:       sig,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									serialized := Marshal(&reply)
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(serialized); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         H,
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   reply.HostKey,
							 | 
						||
| 
								 | 
							
										Signature: sig,
							 | 
						||
| 
								 | 
							
										Hash:      ecHash(kex.curve),
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var kexAlgoMap = map[string]kexAlgorithm{}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func init() {
							 | 
						||
| 
								 | 
							
									// This is the group called diffie-hellman-group1-sha1 in RFC
							 | 
						||
| 
								 | 
							
									// 4253 and Oakley Group 2 in RFC 2409.
							 | 
						||
| 
								 | 
							
									p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
							 | 
						||
| 
								 | 
							
										g:       new(big.Int).SetInt64(2),
							 | 
						||
| 
								 | 
							
										p:       p,
							 | 
						||
| 
								 | 
							
										pMinus1: new(big.Int).Sub(p, bigOne),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// This is the group called diffie-hellman-group14-sha1 in RFC
							 | 
						||
| 
								 | 
							
									// 4253 and Oakley Group 14 in RFC 3526.
							 | 
						||
| 
								 | 
							
									p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
							 | 
						||
| 
								 | 
							
										g:       new(big.Int).SetInt64(2),
							 | 
						||
| 
								 | 
							
										p:       p,
							 | 
						||
| 
								 | 
							
										pMinus1: new(big.Int).Sub(p, bigOne),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
							 | 
						||
| 
								 | 
							
									kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// curve25519sha256 implements the curve25519-sha256@libssh.org key
							 | 
						||
| 
								 | 
							
								// agreement protocol, as described in
							 | 
						||
| 
								 | 
							
								// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
							 | 
						||
| 
								 | 
							
								type curve25519sha256 struct{}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type curve25519KeyPair struct {
							 | 
						||
| 
								 | 
							
									priv [32]byte
							 | 
						||
| 
								 | 
							
									pub  [32]byte
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (kp *curve25519KeyPair) generate(rand io.Reader) error {
							 | 
						||
| 
								 | 
							
									if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									curve25519.ScalarBaseMult(&kp.pub, &kp.priv)
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// curve25519Zeros is just an array of 32 zero bytes so that we have something
							 | 
						||
| 
								 | 
							
								// convenient to compare against in order to reject curve25519 points with the
							 | 
						||
| 
								 | 
							
								// wrong order.
							 | 
						||
| 
								 | 
							
								var curve25519Zeros [32]byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
							 | 
						||
| 
								 | 
							
									var kp curve25519KeyPair
							 | 
						||
| 
								 | 
							
									if err := kp.generate(rand); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var reply kexECDHReplyMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &reply); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if len(reply.EphemeralPubKey) != 32 {
							 | 
						||
| 
								 | 
							
										return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var servPub, secret [32]byte
							 | 
						||
| 
								 | 
							
									copy(servPub[:], reply.EphemeralPubKey)
							 | 
						||
| 
								 | 
							
									curve25519.ScalarMult(&secret, &kp.priv, &servPub)
							 | 
						||
| 
								 | 
							
									if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
							 | 
						||
| 
								 | 
							
										return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := crypto.SHA256.New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, reply.HostKey)
							 | 
						||
| 
								 | 
							
									writeString(h, kp.pub[:])
							 | 
						||
| 
								 | 
							
									writeString(h, reply.EphemeralPubKey)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ki := new(big.Int).SetBytes(secret[:])
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(ki))
							 | 
						||
| 
								 | 
							
									marshalInt(K, ki)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         h.Sum(nil),
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   reply.HostKey,
							 | 
						||
| 
								 | 
							
										Signature: reply.Signature,
							 | 
						||
| 
								 | 
							
										Hash:      crypto.SHA256,
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var kexInit kexECDHInitMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexInit); err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if len(kexInit.ClientPubKey) != 32 {
							 | 
						||
| 
								 | 
							
										return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var kp curve25519KeyPair
							 | 
						||
| 
								 | 
							
									if err := kp.generate(rand); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var clientPub, secret [32]byte
							 | 
						||
| 
								 | 
							
									copy(clientPub[:], kexInit.ClientPubKey)
							 | 
						||
| 
								 | 
							
									curve25519.ScalarMult(&secret, &kp.priv, &clientPub)
							 | 
						||
| 
								 | 
							
									if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
							 | 
						||
| 
								 | 
							
										return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									hostKeyBytes := priv.PublicKey().Marshal()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := crypto.SHA256.New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, hostKeyBytes)
							 | 
						||
| 
								 | 
							
									writeString(h, kexInit.ClientPubKey)
							 | 
						||
| 
								 | 
							
									writeString(h, kp.pub[:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ki := new(big.Int).SetBytes(secret[:])
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(ki))
							 | 
						||
| 
								 | 
							
									marshalInt(K, ki)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									H := h.Sum(nil)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									sig, err := signAndMarshal(priv, rand, H)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									reply := kexECDHReplyMsg{
							 | 
						||
| 
								 | 
							
										EphemeralPubKey: kp.pub[:],
							 | 
						||
| 
								 | 
							
										HostKey:         hostKeyBytes,
							 | 
						||
| 
								 | 
							
										Signature:       sig,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(Marshal(&reply)); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         H,
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   hostKeyBytes,
							 | 
						||
| 
								 | 
							
										Signature: sig,
							 | 
						||
| 
								 | 
							
										Hash:      crypto.SHA256,
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
							 | 
						||
| 
								 | 
							
								// diffie-hellman-group-exchange-sha256 key agreement protocols,
							 | 
						||
| 
								 | 
							
								// as described in RFC 4419
							 | 
						||
| 
								 | 
							
								type dhGEXSHA struct {
							 | 
						||
| 
								 | 
							
									g, p     *big.Int
							 | 
						||
| 
								 | 
							
									hashFunc crypto.Hash
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									dhGroupExchangeMinimumBits   = 2048
							 | 
						||
| 
								 | 
							
									dhGroupExchangePreferredBits = 2048
							 | 
						||
| 
								 | 
							
									dhGroupExchangeMaximumBits   = 8192
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
							 | 
						||
| 
								 | 
							
									if theirPublic.Sign() <= 0 || theirPublic.Cmp(gex.p) >= 0 {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("ssh: DH parameter out of bounds")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
							 | 
						||
| 
								 | 
							
									// Send GexRequest
							 | 
						||
| 
								 | 
							
									kexDHGexRequest := kexDHGexRequestMsg{
							 | 
						||
| 
								 | 
							
										MinBits:      dhGroupExchangeMinimumBits,
							 | 
						||
| 
								 | 
							
										PreferedBits: dhGroupExchangePreferredBits,
							 | 
						||
| 
								 | 
							
										MaxBits:      dhGroupExchangeMaximumBits,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Receive GexGroup
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var kexDHGexGroup kexDHGexGroupMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexDHGexGroup); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
							 | 
						||
| 
								 | 
							
									if kexDHGexGroup.P.BitLen() < dhGroupExchangeMinimumBits || kexDHGexGroup.P.BitLen() > dhGroupExchangeMaximumBits {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", kexDHGexGroup.P.BitLen())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									gex.p = kexDHGexGroup.P
							 | 
						||
| 
								 | 
							
									gex.g = kexDHGexGroup.G
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Check if g is safe by verifing that g > 1 and g < p - 1
							 | 
						||
| 
								 | 
							
									one := big.NewInt(1)
							 | 
						||
| 
								 | 
							
									var pMinusOne = &big.Int{}
							 | 
						||
| 
								 | 
							
									pMinusOne.Sub(gex.p, one)
							 | 
						||
| 
								 | 
							
									if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("ssh: server provided gex g is not safe")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Send GexInit
							 | 
						||
| 
								 | 
							
									var pHalf = &big.Int{}
							 | 
						||
| 
								 | 
							
									pHalf.Rsh(gex.p, 1)
							 | 
						||
| 
								 | 
							
									x, err := rand.Int(randSource, pHalf)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									X := new(big.Int).Exp(gex.g, x, gex.p)
							 | 
						||
| 
								 | 
							
									kexDHGexInit := kexDHGexInitMsg{
							 | 
						||
| 
								 | 
							
										X: X,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Receive GexReply
							 | 
						||
| 
								 | 
							
									packet, err = c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var kexDHGexReply kexDHGexReplyMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexDHGexReply); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kInt, err := gex.diffieHellman(kexDHGexReply.Y, x)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Check if k is safe by verifing that k > 1 and k < p - 1
							 | 
						||
| 
								 | 
							
									if kInt.Cmp(one) != 1 && kInt.Cmp(pMinusOne) != -1 {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("ssh: derived k is not safe")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := gex.hashFunc.New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, kexDHGexReply.HostKey)
							 | 
						||
| 
								 | 
							
									binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
							 | 
						||
| 
								 | 
							
									binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
							 | 
						||
| 
								 | 
							
									binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
							 | 
						||
| 
								 | 
							
									writeInt(h, gex.p)
							 | 
						||
| 
								 | 
							
									writeInt(h, gex.g)
							 | 
						||
| 
								 | 
							
									writeInt(h, X)
							 | 
						||
| 
								 | 
							
									writeInt(h, kexDHGexReply.Y)
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(kInt))
							 | 
						||
| 
								 | 
							
									marshalInt(K, kInt)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         h.Sum(nil),
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   kexDHGexReply.HostKey,
							 | 
						||
| 
								 | 
							
										Signature: kexDHGexReply.Signature,
							 | 
						||
| 
								 | 
							
										Hash:      gex.hashFunc,
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This is a minimal implementation to satisfy the automated tests.
							 | 
						||
| 
								 | 
							
								func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
							 | 
						||
| 
								 | 
							
									// Receive GexRequest
							 | 
						||
| 
								 | 
							
									packet, err := c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var kexDHGexRequest kexDHGexRequestMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// smoosh the user's preferred size into our own limits
							 | 
						||
| 
								 | 
							
									if kexDHGexRequest.PreferedBits > dhGroupExchangeMaximumBits {
							 | 
						||
| 
								 | 
							
										kexDHGexRequest.PreferedBits = dhGroupExchangeMaximumBits
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if kexDHGexRequest.PreferedBits < dhGroupExchangeMinimumBits {
							 | 
						||
| 
								 | 
							
										kexDHGexRequest.PreferedBits = dhGroupExchangeMinimumBits
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// fix min/max if they're inconsistent.  technically, we could just pout
							 | 
						||
| 
								 | 
							
									// and hang up, but there's no harm in giving them the benefit of the
							 | 
						||
| 
								 | 
							
									// doubt and just picking a bitsize for them.
							 | 
						||
| 
								 | 
							
									if kexDHGexRequest.MinBits > kexDHGexRequest.PreferedBits {
							 | 
						||
| 
								 | 
							
										kexDHGexRequest.MinBits = kexDHGexRequest.PreferedBits
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if kexDHGexRequest.MaxBits < kexDHGexRequest.PreferedBits {
							 | 
						||
| 
								 | 
							
										kexDHGexRequest.MaxBits = kexDHGexRequest.PreferedBits
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Send GexGroup
							 | 
						||
| 
								 | 
							
									// This is the group called diffie-hellman-group14-sha1 in RFC
							 | 
						||
| 
								 | 
							
									// 4253 and Oakley Group 14 in RFC 3526.
							 | 
						||
| 
								 | 
							
									p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
							 | 
						||
| 
								 | 
							
									gex.p = p
							 | 
						||
| 
								 | 
							
									gex.g = big.NewInt(2)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kexDHGexGroup := kexDHGexGroupMsg{
							 | 
						||
| 
								 | 
							
										P: gex.p,
							 | 
						||
| 
								 | 
							
										G: gex.g,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if err := c.writePacket(Marshal(&kexDHGexGroup)); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Receive GexInit
							 | 
						||
| 
								 | 
							
									packet, err = c.readPacket()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var kexDHGexInit kexDHGexInitMsg
							 | 
						||
| 
								 | 
							
									if err = Unmarshal(packet, &kexDHGexInit); err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var pHalf = &big.Int{}
							 | 
						||
| 
								 | 
							
									pHalf.Rsh(gex.p, 1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									y, err := rand.Int(randSource, pHalf)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									Y := new(big.Int).Exp(gex.g, y, gex.p)
							 | 
						||
| 
								 | 
							
									kInt, err := gex.diffieHellman(kexDHGexInit.X, y)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									hostKeyBytes := priv.PublicKey().Marshal()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									h := gex.hashFunc.New()
							 | 
						||
| 
								 | 
							
									magics.write(h)
							 | 
						||
| 
								 | 
							
									writeString(h, hostKeyBytes)
							 | 
						||
| 
								 | 
							
									binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
							 | 
						||
| 
								 | 
							
									binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
							 | 
						||
| 
								 | 
							
									binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
							 | 
						||
| 
								 | 
							
									writeInt(h, gex.p)
							 | 
						||
| 
								 | 
							
									writeInt(h, gex.g)
							 | 
						||
| 
								 | 
							
									writeInt(h, kexDHGexInit.X)
							 | 
						||
| 
								 | 
							
									writeInt(h, Y)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									K := make([]byte, intLength(kInt))
							 | 
						||
| 
								 | 
							
									marshalInt(K, kInt)
							 | 
						||
| 
								 | 
							
									h.Write(K)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									H := h.Sum(nil)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// H is already a hash, but the hostkey signing will apply its
							 | 
						||
| 
								 | 
							
									// own key-specific hash algorithm.
							 | 
						||
| 
								 | 
							
									sig, err := signAndMarshal(priv, randSource, H)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kexDHGexReply := kexDHGexReplyMsg{
							 | 
						||
| 
								 | 
							
										HostKey:   hostKeyBytes,
							 | 
						||
| 
								 | 
							
										Y:         Y,
							 | 
						||
| 
								 | 
							
										Signature: sig,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									packet = Marshal(&kexDHGexReply)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = c.writePacket(packet)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &kexResult{
							 | 
						||
| 
								 | 
							
										H:         H,
							 | 
						||
| 
								 | 
							
										K:         K,
							 | 
						||
| 
								 | 
							
										HostKey:   hostKeyBytes,
							 | 
						||
| 
								 | 
							
										Signature: sig,
							 | 
						||
| 
								 | 
							
										Hash:      gex.hashFunc,
							 | 
						||
| 
								 | 
							
									}, err
							 | 
						||
| 
								 | 
							
								}
							 |