// 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 (
	
	
	
	
	
	
	
)

// debugHandshake, if set, prints messages sent and received.  Key
// exchange messages are printed as if DH were used, so the debug
// messages are wrong when using ECDH.
const debugHandshake = false

// chanSize sets the amount of buffering SSH connections. This is
// primarily for testing: setting chanSize=0 uncovers deadlocks more
// quickly.
const chanSize = 16

// keyingTransport is a packet based transport that supports key
// changes. It need not be thread-safe. It should pass through
// msgNewKeys in both directions.
type keyingTransport interface {
	packetConn

	// prepareKeyChange sets up a key change. The key change for a
	// direction will be effected if a msgNewKeys message is sent
	// or received.
	prepareKeyChange(*algorithms, *kexResult) error
}

// handshakeTransport implements rekeying on top of a keyingTransport
// and offers a thread-safe writePacket() interface.
type handshakeTransport struct {
	conn   keyingTransport
	config *Config

	serverVersion []byte
	clientVersion []byte

	// hostKeys is non-empty if we are the server. In that case,
	// it contains all host keys that can be used to sign the
	// connection.
	hostKeys []Signer

	// hostKeyAlgorithms is non-empty if we are the client. In that case,
	// we accept these key types from the server as host key.
	hostKeyAlgorithms []string

	// On read error, incoming is closed, and readError is set.
	incoming  chan []byte
	readError error

	mu               sync.Mutex
	writeError       error
	sentInitPacket   []byte
	sentInitMsg      *kexInitMsg
	pendingPackets   [][]byte // Used when a key exchange is in progress.
	writePacketsLeft uint32
	writeBytesLeft   int64

	// If the read loop wants to schedule a kex, it pings this
	// channel, and the write loop will send out a kex
	// message.
	requestKex chan struct{}

	// If the other side requests or confirms a kex, its kexInit
	// packet is sent here for the write loop to find it.
	startKex    chan *pendingKex
	kexLoopDone chan struct{} // closed (with writeError non-nil) when kexLoop exits

	// data for host key checking
	hostKeyCallback HostKeyCallback
	dialAddress     string
	remoteAddr      net.Addr

	// bannerCallback is non-empty if we are the client and it has been set in
	// ClientConfig. In that case it is called during the user authentication
	// dance to handle a custom server's message.
	bannerCallback BannerCallback

	// Algorithms agreed in the last key exchange.
	algorithms *algorithms

	// Counters exclusively owned by readLoop.
	readPacketsLeft uint32
	readBytesLeft   int64

	// The session ID or nil if first kex did not complete yet.
	sessionID []byte
}

type pendingKex struct {
	otherInit []byte
	done      chan error
}

func newHandshakeTransport( keyingTransport,  *Config, ,  []byte) *handshakeTransport {
	 := &handshakeTransport{
		conn:          ,
		serverVersion: ,
		clientVersion: ,
		incoming:      make(chan []byte, chanSize),
		requestKex:    make(chan struct{}, 1),
		startKex:      make(chan *pendingKex),
		kexLoopDone:   make(chan struct{}),

		config: ,
	}
	.resetReadThresholds()
	.resetWriteThresholds()

	// We always start with a mandatory key exchange.
	.requestKex <- struct{}{}
	return 
}

func newClientTransport( keyingTransport, ,  []byte,  *ClientConfig,  string,  net.Addr) *handshakeTransport {
	 := newHandshakeTransport(, &.Config, , )
	.dialAddress = 
	.remoteAddr = 
	.hostKeyCallback = .HostKeyCallback
	.bannerCallback = .BannerCallback
	if .HostKeyAlgorithms != nil {
		.hostKeyAlgorithms = .HostKeyAlgorithms
	} else {
		.hostKeyAlgorithms = supportedHostKeyAlgos
	}
	go .readLoop()
	go .kexLoop()
	return 
}

func newServerTransport( keyingTransport, ,  []byte,  *ServerConfig) *handshakeTransport {
	 := newHandshakeTransport(, &.Config, , )
	.hostKeys = .hostKeys
	go .readLoop()
	go .kexLoop()
	return 
}

func ( *handshakeTransport) () []byte {
	return .sessionID
}

// waitSession waits for the session to be established. This should be
// the first thing to call after instantiating handshakeTransport.
func ( *handshakeTransport) () error {
	,  := .readPacket()
	if  != nil {
		return 
	}
	if [0] != msgNewKeys {
		return fmt.Errorf("ssh: first packet should be msgNewKeys")
	}

	return nil
}

func ( *handshakeTransport) () string {
	if len(.hostKeys) > 0 {
		return "server"
	}
	return "client"
}

func ( *handshakeTransport) ( []byte,  bool) {
	 := "got"
	if  {
		 = "sent"
	}

	if [0] == msgChannelData || [0] == msgChannelExtendedData {
		log.Printf("%s %s data (packet %d bytes)", .id(), , len())
	} else {
		,  := decode()
		log.Printf("%s %s %T %v (%v)", .id(), , , , )
	}
}

func ( *handshakeTransport) () ([]byte, error) {
	,  := <-.incoming
	if ! {
		return nil, .readError
	}
	return , nil
}

func ( *handshakeTransport) () {
	 := true
	for {
		,  := .readOnePacket()
		 = false
		if  != nil {
			.readError = 
			close(.incoming)
			break
		}
		if [0] == msgIgnore || [0] == msgDebug {
			continue
		}
		.incoming <- 
	}

	// Stop writers too.
	.recordWriteError(.readError)

	// Unblock the writer should it wait for this.
	close(.startKex)

	// Don't close t.requestKex; it's also written to from writePacket.
}

func ( *handshakeTransport) ( []byte) error {
	if debugHandshake {
		.printPacket(, true)
	}
	return .conn.writePacket()
}

func ( *handshakeTransport) () error {
	.mu.Lock()
	defer .mu.Unlock()
	return .writeError
}

func ( *handshakeTransport) ( error) {
	.mu.Lock()
	defer .mu.Unlock()
	if .writeError == nil &&  != nil {
		.writeError = 
	}
}

func ( *handshakeTransport) () {
	select {
	case .requestKex <- struct{}{}:
	default:
		// something already requested a kex, so do nothing.
	}
}

func ( *handshakeTransport) () {
	.writePacketsLeft = packetRekeyThreshold
	if .config.RekeyThreshold > 0 {
		.writeBytesLeft = int64(.config.RekeyThreshold)
	} else if .algorithms != nil {
		.writeBytesLeft = .algorithms.w.rekeyBytes()
	} else {
		.writeBytesLeft = 1 << 30
	}
}

func ( *handshakeTransport) () {

:
	for .getWriteError() == nil {
		var  *pendingKex
		var  bool

		for  == nil || ! {
			var  bool
			select {
			case ,  = <-.startKex:
				if ! {
					break 
				}
			case <-.requestKex:
				break
			}

			if ! {
				if  := .sendKexInit();  != nil {
					.recordWriteError()
					break
				}
				 = true
			}
		}

		if  := .getWriteError();  != nil {
			if  != nil {
				.done <- 
			}
			break
		}

		// We're not servicing t.requestKex, but that is OK:
		// we never block on sending to t.requestKex.

		// We're not servicing t.startKex, but the remote end
		// has just sent us a kexInitMsg, so it can't send
		// another key change request, until we close the done
		// channel on the pendingKex request.

		 := .enterKeyExchange(.otherInit)

		.mu.Lock()
		.writeError = 
		.sentInitPacket = nil
		.sentInitMsg = nil

		.resetWriteThresholds()

		// we have completed the key exchange. Since the
		// reader is still blocked, it is safe to clear out
		// the requestKex channel. This avoids the situation
		// where: 1) we consumed our own request for the
		// initial kex, and 2) the kex from the remote side
		// caused another send on the requestKex channel,
	:
		for {
			select {
			case <-.requestKex:
				//
			default:
				break 
			}
		}

		.done <- .writeError

		// kex finished. Push packets that we received while
		// the kex was in progress. Don't look at t.startKex
		// and don't increment writtenSinceKex: if we trigger
		// another kex while we are still busy with the last
		// one, things will become very confusing.
		for ,  := range .pendingPackets {
			.writeError = .pushPacket()
			if .writeError != nil {
				break
			}
		}
		.pendingPackets = .pendingPackets[:0]
		.mu.Unlock()
	}

	// Unblock reader.
	.conn.Close()

	// drain startKex channel. We don't service t.requestKex
	// because nobody does blocking sends there.
	for  := range .startKex {
		.done <- .getWriteError()
	}

	// Mark that the loop is done so that Close can return.
	close(.kexLoopDone)
}

// The protocol uses uint32 for packet counters, so we can't let them
// reach 1<<32.  We will actually read and write more packets than
// this, though: the other side may send more packets, and after we
// hit this limit on writing we will send a few more packets for the
// key exchange itself.
const packetRekeyThreshold = (1 << 31)

func ( *handshakeTransport) () {
	.readPacketsLeft = packetRekeyThreshold
	if .config.RekeyThreshold > 0 {
		.readBytesLeft = int64(.config.RekeyThreshold)
	} else if .algorithms != nil {
		.readBytesLeft = .algorithms.r.rekeyBytes()
	} else {
		.readBytesLeft = 1 << 30
	}
}

func ( *handshakeTransport) ( bool) ([]byte, error) {
	,  := .conn.readPacket()
	if  != nil {
		return nil, 
	}

	if .readPacketsLeft > 0 {
		.readPacketsLeft--
	} else {
		.requestKeyExchange()
	}

	if .readBytesLeft > 0 {
		.readBytesLeft -= int64(len())
	} else {
		.requestKeyExchange()
	}

	if debugHandshake {
		.printPacket(, false)
	}

	if  && [0] != msgKexInit {
		return nil, fmt.Errorf("ssh: first packet should be msgKexInit")
	}

	if [0] != msgKexInit {
		return , nil
	}

	 := .sessionID == nil

	 := pendingKex{
		done:      make(chan error, 1),
		otherInit: ,
	}
	.startKex <- &
	 = <-.done

	if debugHandshake {
		log.Printf("%s exited key exchange (first %v), err %v", .id(), , )
	}

	if  != nil {
		return nil, 
	}

	.resetReadThresholds()

	// By default, a key exchange is hidden from higher layers by
	// translating it into msgIgnore.
	 := []byte{msgIgnore}
	if  {
		// sendKexInit() for the first kex waits for
		// msgNewKeys so the authentication process is
		// guaranteed to happen over an encrypted transport.
		 = []byte{msgNewKeys}
	}

	return , nil
}

// sendKexInit sends a key change message.
func ( *handshakeTransport) () error {
	.mu.Lock()
	defer .mu.Unlock()
	if .sentInitMsg != nil {
		// kexInits may be sent either in response to the other side,
		// or because our side wants to initiate a key change, so we
		// may have already sent a kexInit. In that case, don't send a
		// second kexInit.
		return nil
	}

	 := &kexInitMsg{
		KexAlgos:                .config.KeyExchanges,
		CiphersClientServer:     .config.Ciphers,
		CiphersServerClient:     .config.Ciphers,
		MACsClientServer:        .config.MACs,
		MACsServerClient:        .config.MACs,
		CompressionClientServer: supportedCompressions,
		CompressionServerClient: supportedCompressions,
	}
	io.ReadFull(rand.Reader, .Cookie[:])

	 := len(.hostKeys) > 0
	if  {
		for ,  := range .hostKeys {
			// If k is a MultiAlgorithmSigner, we restrict the signature
			// algorithms. If k is a AlgorithmSigner, presume it supports all
			// signature algorithms associated with the key format. If k is not
			// an AlgorithmSigner, we can only assume it only supports the
			// algorithms that matches the key format. (This means that Sign
			// can't pick a different default).
			 := .PublicKey().Type()

			switch s := .(type) {
			case MultiAlgorithmSigner:
				for ,  := range algorithmsForKeyFormat() {
					if contains(.Algorithms(), underlyingAlgo()) {
						.ServerHostKeyAlgos = append(.ServerHostKeyAlgos, )
					}
				}
			case AlgorithmSigner:
				.ServerHostKeyAlgos = append(.ServerHostKeyAlgos, algorithmsForKeyFormat()...)
			default:
				.ServerHostKeyAlgos = append(.ServerHostKeyAlgos, )
			}
		}
	} else {
		.ServerHostKeyAlgos = .hostKeyAlgorithms

		// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
		// algorithms the server supports for public key authentication. See RFC
		// 8308, Section 2.1.
		if  := .sessionID == nil;  {
			.KexAlgos = make([]string, 0, len(.config.KeyExchanges)+1)
			.KexAlgos = append(.KexAlgos, .config.KeyExchanges...)
			.KexAlgos = append(.KexAlgos, "ext-info-c")
		}
	}

	 := Marshal()

	// writePacket destroys the contents, so save a copy.
	 := make([]byte, len())
	copy(, )

	if  := .pushPacket();  != nil {
		return 
	}

	.sentInitMsg = 
	.sentInitPacket = 

	return nil
}

func ( *handshakeTransport) ( []byte) error {
	switch [0] {
	case msgKexInit:
		return errors.New("ssh: only handshakeTransport can send kexInit")
	case msgNewKeys:
		return errors.New("ssh: only handshakeTransport can send newKeys")
	}

	.mu.Lock()
	defer .mu.Unlock()
	if .writeError != nil {
		return .writeError
	}

	if .sentInitMsg != nil {
		// Copy the packet so the writer can reuse the buffer.
		 := make([]byte, len())
		copy(, )
		.pendingPackets = append(.pendingPackets, )
		return nil
	}

	if .writeBytesLeft > 0 {
		.writeBytesLeft -= int64(len())
	} else {
		.requestKeyExchange()
	}

	if .writePacketsLeft > 0 {
		.writePacketsLeft--
	} else {
		.requestKeyExchange()
	}

	if  := .pushPacket();  != nil {
		.writeError = 
	}

	return nil
}

func ( *handshakeTransport) () error {
	// Close the connection. This should cause the readLoop goroutine to wake up
	// and close t.startKex, which will shut down kexLoop if running.
	 := .conn.Close()

	// Wait for the kexLoop goroutine to complete.
	// At that point we know that the readLoop goroutine is complete too,
	// because kexLoop itself waits for readLoop to close the startKex channel.
	<-.kexLoopDone

	return 
}

func ( *handshakeTransport) ( []byte) error {
	if debugHandshake {
		log.Printf("%s entered key exchange", .id())
	}

	 := &kexInitMsg{}
	if  := Unmarshal(, );  != nil {
		return 
	}

	 := handshakeMagics{
		clientVersion: .clientVersion,
		serverVersion: .serverVersion,
		clientKexInit: ,
		serverKexInit: .sentInitPacket,
	}

	 := 
	 := .sentInitMsg
	 := len(.hostKeys) == 0
	if  {
		,  = , 

		.clientKexInit = .sentInitPacket
		.serverKexInit = 
	}

	var  error
	.algorithms,  = findAgreedAlgorithms(, , )
	if  != nil {
		return 
	}

	// We don't send FirstKexFollows, but we handle receiving it.
	//
	// RFC 4253 section 7 defines the kex and the agreement method for
	// first_kex_packet_follows. It states that the guessed packet
	// should be ignored if the "kex algorithm and/or the host
	// key algorithm is guessed wrong (server and client have
	// different preferred algorithm), or if any of the other
	// algorithms cannot be agreed upon". The other algorithms have
	// already been checked above so the kex algorithm and host key
	// algorithm are checked here.
	if .FirstKexFollows && (.KexAlgos[0] != .KexAlgos[0] || .ServerHostKeyAlgos[0] != .ServerHostKeyAlgos[0]) {
		// other side sent a kex message for the wrong algorithm,
		// which we have to ignore.
		if ,  := .conn.readPacket();  != nil {
			return 
		}
	}

	,  := kexAlgoMap[.algorithms.kex]
	if ! {
		return fmt.Errorf("ssh: unexpected key exchange algorithm %v", .algorithms.kex)
	}

	var  *kexResult
	if len(.hostKeys) > 0 {
		,  = .server(, &)
	} else {
		,  = .client(, &)
	}

	if  != nil {
		return 
	}

	 := .sessionID == nil
	if  {
		.sessionID = .H
	}
	.SessionID = .sessionID

	if  := .conn.prepareKeyChange(.algorithms, );  != nil {
		return 
	}
	if  = .conn.writePacket([]byte{msgNewKeys});  != nil {
		return 
	}

	// On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO
	// message with the server-sig-algs extension if the client supports it. See
	// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
	if ! &&  && contains(.KexAlgos, "ext-info-c") {
		 := &extInfoMsg{
			NumExtensions: 2,
			Payload:       make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1),
		}
		.Payload = appendInt(.Payload, len("server-sig-algs"))
		.Payload = append(.Payload, "server-sig-algs"...)
		.Payload = appendInt(.Payload, len(supportedPubKeyAuthAlgosList))
		.Payload = append(.Payload, supportedPubKeyAuthAlgosList...)
		.Payload = appendInt(.Payload, len("ping@openssh.com"))
		.Payload = append(.Payload, "ping@openssh.com"...)
		.Payload = appendInt(.Payload, 1)
		.Payload = append(.Payload, "0"...)
		if  := .conn.writePacket(Marshal());  != nil {
			return 
		}
	}

	if ,  := .conn.readPacket();  != nil {
		return 
	} else if [0] != msgNewKeys {
		return unexpectedMessageError(msgNewKeys, [0])
	}

	return nil
}

// algorithmSignerWrapper is an AlgorithmSigner that only supports the default
// key format algorithm.
//
// This is technically a violation of the AlgorithmSigner interface, but it
// should be unreachable given where we use this. Anyway, at least it returns an
// error instead of panicing or producing an incorrect signature.
type algorithmSignerWrapper struct {
	Signer
}

func ( algorithmSignerWrapper) ( io.Reader,  []byte,  string) (*Signature, error) {
	if  != underlyingAlgo(.PublicKey().Type()) {
		return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm")
	}
	return .Sign(, )
}

func pickHostKey( []Signer,  string) AlgorithmSigner {
	for ,  := range  {
		if ,  := .(MultiAlgorithmSigner);  {
			if !contains(.Algorithms(), underlyingAlgo()) {
				continue
			}
		}

		if  == .PublicKey().Type() {
			return algorithmSignerWrapper{}
		}

		,  := .(AlgorithmSigner)
		if ! {
			continue
		}
		for ,  := range algorithmsForKeyFormat(.PublicKey().Type()) {
			if  ==  {
				return 
			}
		}
	}
	return nil
}

func ( *handshakeTransport) ( kexAlgorithm,  *handshakeMagics) (*kexResult, error) {
	 := pickHostKey(.hostKeys, .algorithms.hostKey)
	if  == nil {
		return nil, errors.New("ssh: internal error: negotiated unsupported signature type")
	}

	,  := .Server(.conn, .config.Rand, , , .algorithms.hostKey)
	return , 
}

func ( *handshakeTransport) ( kexAlgorithm,  *handshakeMagics) (*kexResult, error) {
	,  := .Client(.conn, .config.Rand, )
	if  != nil {
		return nil, 
	}

	,  := ParsePublicKey(.HostKey)
	if  != nil {
		return nil, 
	}

	if  := verifyHostKeySignature(, .algorithms.hostKey, );  != nil {
		return nil, 
	}

	 = .hostKeyCallback(.dialAddress, .remoteAddr, )
	if  != nil {
		return nil, 
	}

	return , nil
}