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

// These are SSH message type numbers. They are scattered around several
// documents but many were taken from [SSH-PARAMETERS].
const (
	msgIgnore        = 2
	msgUnimplemented = 3
	msgDebug         = 4
	msgNewKeys       = 21
)

// SSH messages:
//
// These structures mirror the wire format of the corresponding SSH messages.
// They are marshaled using reflection with the marshal and unmarshal functions
// in this file. The only wrinkle is that a final member of type []byte with a
// ssh tag of "rest" receives the remainder of a packet when unmarshaling.

// See RFC 4253, section 11.1.
const msgDisconnect = 1

// disconnectMsg is the message that signals a disconnect. It is also
// the error type returned from mux.Wait()
type disconnectMsg struct {
	Reason   uint32 `sshtype:"1"`
	Message  string
	Language string
}

func ( *disconnectMsg) () string {
	return fmt.Sprintf("ssh: disconnect, reason %d: %s", .Reason, .Message)
}

// See RFC 4253, section 7.1.
const msgKexInit = 20

type kexInitMsg struct {
	Cookie                  [16]byte `sshtype:"20"`
	KexAlgos                []string
	ServerHostKeyAlgos      []string
	CiphersClientServer     []string
	CiphersServerClient     []string
	MACsClientServer        []string
	MACsServerClient        []string
	CompressionClientServer []string
	CompressionServerClient []string
	LanguagesClientServer   []string
	LanguagesServerClient   []string
	FirstKexFollows         bool
	Reserved                uint32
}

// See RFC 4253, section 8.

// Diffie-Hellman
const msgKexDHInit = 30

type kexDHInitMsg struct {
	X *big.Int `sshtype:"30"`
}

const msgKexECDHInit = 30

type kexECDHInitMsg struct {
	ClientPubKey []byte `sshtype:"30"`
}

const msgKexECDHReply = 31

type kexECDHReplyMsg struct {
	HostKey         []byte `sshtype:"31"`
	EphemeralPubKey []byte
	Signature       []byte
}

const msgKexDHReply = 31

type kexDHReplyMsg struct {
	HostKey   []byte `sshtype:"31"`
	Y         *big.Int
	Signature []byte
}

// See RFC 4419, section 5.
const msgKexDHGexGroup = 31

type kexDHGexGroupMsg struct {
	P *big.Int `sshtype:"31"`
	G *big.Int
}

const msgKexDHGexInit = 32

type kexDHGexInitMsg struct {
	X *big.Int `sshtype:"32"`
}

const msgKexDHGexReply = 33

type kexDHGexReplyMsg struct {
	HostKey   []byte `sshtype:"33"`
	Y         *big.Int
	Signature []byte
}

const msgKexDHGexRequest = 34

type kexDHGexRequestMsg struct {
	MinBits      uint32 `sshtype:"34"`
	PreferedBits uint32
	MaxBits      uint32
}

// See RFC 4253, section 10.
const msgServiceRequest = 5

type serviceRequestMsg struct {
	Service string `sshtype:"5"`
}

// See RFC 4253, section 10.
const msgServiceAccept = 6

type serviceAcceptMsg struct {
	Service string `sshtype:"6"`
}

// See RFC 8308, section 2.3
const msgExtInfo = 7

type extInfoMsg struct {
	NumExtensions uint32 `sshtype:"7"`
	Payload       []byte `ssh:"rest"`
}

// See RFC 4252, section 5.
const msgUserAuthRequest = 50

type userAuthRequestMsg struct {
	User    string `sshtype:"50"`
	Service string
	Method  string
	Payload []byte `ssh:"rest"`
}

// Used for debug printouts of packets.
type userAuthSuccessMsg struct {
}

// See RFC 4252, section 5.1
const msgUserAuthFailure = 51

type userAuthFailureMsg struct {
	Methods        []string `sshtype:"51"`
	PartialSuccess bool
}

// See RFC 4252, section 5.1
const msgUserAuthSuccess = 52

// See RFC 4252, section 5.4
const msgUserAuthBanner = 53

type userAuthBannerMsg struct {
	Message string `sshtype:"53"`
	// unused, but required to allow message parsing
	Language string
}

// See RFC 4256, section 3.2
const msgUserAuthInfoRequest = 60
const msgUserAuthInfoResponse = 61

type userAuthInfoRequestMsg struct {
	Name        string `sshtype:"60"`
	Instruction string
	Language    string
	NumPrompts  uint32
	Prompts     []byte `ssh:"rest"`
}

// See RFC 4254, section 5.1.
const msgChannelOpen = 90

type channelOpenMsg struct {
	ChanType         string `sshtype:"90"`
	PeersID          uint32
	PeersWindow      uint32
	MaxPacketSize    uint32
	TypeSpecificData []byte `ssh:"rest"`
}

const msgChannelExtendedData = 95
const msgChannelData = 94

// Used for debug print outs of packets.
type channelDataMsg struct {
	PeersID uint32 `sshtype:"94"`
	Length  uint32
	Rest    []byte `ssh:"rest"`
}

// See RFC 4254, section 5.1.
const msgChannelOpenConfirm = 91

type channelOpenConfirmMsg struct {
	PeersID          uint32 `sshtype:"91"`
	MyID             uint32
	MyWindow         uint32
	MaxPacketSize    uint32
	TypeSpecificData []byte `ssh:"rest"`
}

// See RFC 4254, section 5.1.
const msgChannelOpenFailure = 92

type channelOpenFailureMsg struct {
	PeersID  uint32 `sshtype:"92"`
	Reason   RejectionReason
	Message  string
	Language string
}

const msgChannelRequest = 98

type channelRequestMsg struct {
	PeersID             uint32 `sshtype:"98"`
	Request             string
	WantReply           bool
	RequestSpecificData []byte `ssh:"rest"`
}

// See RFC 4254, section 5.4.
const msgChannelSuccess = 99

type channelRequestSuccessMsg struct {
	PeersID uint32 `sshtype:"99"`
}

// See RFC 4254, section 5.4.
const msgChannelFailure = 100

type channelRequestFailureMsg struct {
	PeersID uint32 `sshtype:"100"`
}

// See RFC 4254, section 5.3
const msgChannelClose = 97

type channelCloseMsg struct {
	PeersID uint32 `sshtype:"97"`
}

// See RFC 4254, section 5.3
const msgChannelEOF = 96

type channelEOFMsg struct {
	PeersID uint32 `sshtype:"96"`
}

// See RFC 4254, section 4
const msgGlobalRequest = 80

type globalRequestMsg struct {
	Type      string `sshtype:"80"`
	WantReply bool
	Data      []byte `ssh:"rest"`
}

// See RFC 4254, section 4
const msgRequestSuccess = 81

type globalRequestSuccessMsg struct {
	Data []byte `ssh:"rest" sshtype:"81"`
}

// See RFC 4254, section 4
const msgRequestFailure = 82

type globalRequestFailureMsg struct {
	Data []byte `ssh:"rest" sshtype:"82"`
}

// See RFC 4254, section 5.2
const msgChannelWindowAdjust = 93

type windowAdjustMsg struct {
	PeersID         uint32 `sshtype:"93"`
	AdditionalBytes uint32
}

// See RFC 4252, section 7
const msgUserAuthPubKeyOk = 60

type userAuthPubKeyOkMsg struct {
	Algo   string `sshtype:"60"`
	PubKey []byte
}

// See RFC 4462, section 3
const msgUserAuthGSSAPIResponse = 60

type userAuthGSSAPIResponse struct {
	SupportMech []byte `sshtype:"60"`
}

const msgUserAuthGSSAPIToken = 61

type userAuthGSSAPIToken struct {
	Token []byte `sshtype:"61"`
}

const msgUserAuthGSSAPIMIC = 66

type userAuthGSSAPIMIC struct {
	MIC []byte `sshtype:"66"`
}

// See RFC 4462, section 3.9
const msgUserAuthGSSAPIErrTok = 64

type userAuthGSSAPIErrTok struct {
	ErrorToken []byte `sshtype:"64"`
}

// See RFC 4462, section 3.8
const msgUserAuthGSSAPIError = 65

type userAuthGSSAPIError struct {
	MajorStatus uint32 `sshtype:"65"`
	MinorStatus uint32
	Message     string
	LanguageTag string
}

// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPing = 192

type pingMsg struct {
	Data string `sshtype:"192"`
}

// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPong = 193

type pongMsg struct {
	Data string `sshtype:"193"`
}

// typeTags returns the possible type bytes for the given reflect.Type, which
// should be a struct. The possible values are separated by a '|' character.
func typeTags( reflect.Type) ( []byte) {
	 := .Field(0).Tag.Get("sshtype")

	for ,  := range strings.Split(, "|") {
		,  := strconv.Atoi()
		if  == nil {
			 = append(, byte())
		}
	}

	return 
}

func fieldError( reflect.Type,  int,  string) error {
	if  != "" {
		 = ": " + 
	}
	return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", .Field().Name, .Name(), )
}

var errShortRead = errors.New("ssh: short read")

// Unmarshal parses data in SSH wire format into a structure. The out
// argument should be a pointer to struct. If the first member of the
// struct has the "sshtype" tag set to a '|'-separated set of numbers
// in decimal, the packet must start with one of those numbers. In
// case of error, Unmarshal returns a ParseError or
// UnexpectedMessageError.
func ( []byte,  interface{}) error {
	 := reflect.ValueOf().Elem()
	 := .Type()
	 := typeTags()

	var  byte
	if len() > 0 {
		 = [0]
	}

	if len() == 0 {
		return parseError()
	}

	if len() > 0 {
		 := false
		for ,  := range  {
			if  > 0 && [0] ==  {
				 = true
				break
			}
		}
		if ! {
			return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", [0], )
		}
		 = [1:]
	}

	var  bool
	for  := 0;  < .NumField(); ++ {
		 := .Field()
		 := .Type()
		switch .Kind() {
		case reflect.Bool:
			if len() < 1 {
				return errShortRead
			}
			.SetBool([0] != 0)
			 = [1:]
		case reflect.Array:
			if .Elem().Kind() != reflect.Uint8 {
				return fieldError(, , "array of unsupported type")
			}
			if len() < .Len() {
				return errShortRead
			}
			for ,  := 0, .Len();  < ; ++ {
				.Index().Set(reflect.ValueOf([]))
			}
			 = [.Len():]
		case reflect.Uint64:
			var  uint64
			if , ,  = parseUint64(); ! {
				return errShortRead
			}
			.SetUint()
		case reflect.Uint32:
			var  uint32
			if , ,  = parseUint32(); ! {
				return errShortRead
			}
			.SetUint(uint64())
		case reflect.Uint8:
			if len() < 1 {
				return errShortRead
			}
			.SetUint(uint64([0]))
			 = [1:]
		case reflect.String:
			var  []byte
			if , ,  = parseString(); ! {
				return fieldError(, , "")
			}
			.SetString(string())
		case reflect.Slice:
			switch .Elem().Kind() {
			case reflect.Uint8:
				if .Field().Tag.Get("ssh") == "rest" {
					.Set(reflect.ValueOf())
					 = nil
				} else {
					var  []byte
					if , ,  = parseString(); ! {
						return errShortRead
					}
					.Set(reflect.ValueOf())
				}
			case reflect.String:
				var  []string
				if , ,  = parseNameList(); ! {
					return errShortRead
				}
				.Set(reflect.ValueOf())
			default:
				return fieldError(, , "slice of unsupported type")
			}
		case reflect.Ptr:
			if  == bigIntType {
				var  *big.Int
				if , ,  = parseInt(); ! {
					return errShortRead
				}
				.Set(reflect.ValueOf())
			} else {
				return fieldError(, , "pointer to unsupported type")
			}
		default:
			return fieldError(, , fmt.Sprintf("unsupported type: %v", ))
		}
	}

	if len() != 0 {
		return parseError()
	}

	return nil
}

// Marshal serializes the message in msg to SSH wire format.  The msg
// argument should be a struct or pointer to struct. If the first
// member has the "sshtype" tag set to a number in decimal, that
// number is prepended to the result. If the last of member has the
// "ssh" tag set to "rest", its contents are appended to the output.
func ( interface{}) []byte {
	 := make([]byte, 0, 64)
	return marshalStruct(, )
}

func marshalStruct( []byte,  interface{}) []byte {
	 := reflect.Indirect(reflect.ValueOf())
	 := typeTags(.Type())
	if len() > 0 {
		 = append(, [0])
	}

	for ,  := 0, .NumField();  < ; ++ {
		 := .Field()
		switch  := .Type(); .Kind() {
		case reflect.Bool:
			var  uint8
			if .Bool() {
				 = 1
			}
			 = append(, )
		case reflect.Array:
			if .Elem().Kind() != reflect.Uint8 {
				panic(fmt.Sprintf("array of non-uint8 in field %d: %T", , .Interface()))
			}
			for ,  := 0, .Len();  < ; ++ {
				 = append(, uint8(.Index().Uint()))
			}
		case reflect.Uint32:
			 = appendU32(, uint32(.Uint()))
		case reflect.Uint64:
			 = appendU64(, uint64(.Uint()))
		case reflect.Uint8:
			 = append(, uint8(.Uint()))
		case reflect.String:
			 := .String()
			 = appendInt(, len())
			 = append(, ...)
		case reflect.Slice:
			switch .Elem().Kind() {
			case reflect.Uint8:
				if .Type().Field().Tag.Get("ssh") != "rest" {
					 = appendInt(, .Len())
				}
				 = append(, .Bytes()...)
			case reflect.String:
				 := len()
				 = appendU32(, 0)
				if  := .Len();  > 0 {
					for  := 0;  < ; ++ {
						 := .Index()
						if  != 0 {
							 = append(, ',')
						}
						 = append(, .String()...)
					}
					// overwrite length value
					binary.BigEndian.PutUint32([:], uint32(len()--4))
				}
			default:
				panic(fmt.Sprintf("slice of unknown type in field %d: %T", , .Interface()))
			}
		case reflect.Ptr:
			if  == bigIntType {
				var  *big.Int
				 := reflect.ValueOf(&)
				.Elem().Set()
				 := intLength()
				 := len()

				if cap()-len() <  {
					 := make([]byte, len(), 2*(len()+))
					copy(, )
					 = 
				}
				 = [:+]
				marshalInt([:], )
			} else {
				panic(fmt.Sprintf("pointer to unknown type in field %d: %T", , .Interface()))
			}
		}
	}

	return 
}

var bigOne = big.NewInt(1)

func parseString( []byte) (,  []byte,  bool) {
	if len() < 4 {
		return
	}
	 := binary.BigEndian.Uint32()
	 = [4:]
	if uint32(len()) <  {
		return
	}
	 = [:]
	 = [:]
	 = true
	return
}

var (
	comma         = []byte{','}
	emptyNameList = []string{}
)

func parseNameList( []byte) ( []string,  []byte,  bool) {
	, ,  := parseString()
	if ! {
		return
	}
	if len() == 0 {
		 = emptyNameList
		return
	}
	 := bytes.Split(, comma)
	 = make([]string, len())
	for ,  := range  {
		[] = string()
	}
	return
}

func parseInt( []byte) ( *big.Int,  []byte,  bool) {
	, ,  := parseString()
	if ! {
		return
	}
	 = new(big.Int)

	if len() > 0 && [0]&0x80 == 0x80 {
		// This is a negative number
		 := make([]byte, len())
		for  := range  {
			[] = ^[]
		}
		.SetBytes()
		.Add(, bigOne)
		.Neg()
	} else {
		// Positive number
		.SetBytes()
	}
	 = true
	return
}

func parseUint32( []byte) (uint32, []byte, bool) {
	if len() < 4 {
		return 0, nil, false
	}
	return binary.BigEndian.Uint32(), [4:], true
}

func parseUint64( []byte) (uint64, []byte, bool) {
	if len() < 8 {
		return 0, nil, false
	}
	return binary.BigEndian.Uint64(), [8:], true
}

func intLength( *big.Int) int {
	 := 4 /* length bytes */
	if .Sign() < 0 {
		 := new(big.Int).Neg()
		.Sub(, bigOne)
		 := .BitLen()
		if %8 == 0 {
			// The number will need 0xff padding
			++
		}
		 += ( + 7) / 8
	} else if .Sign() == 0 {
		// A zero is the zero length string
	} else {
		 := .BitLen()
		if %8 == 0 {
			// The number will need 0x00 padding
			++
		}
		 += ( + 7) / 8
	}

	return 
}

func marshalUint32( []byte,  uint32) []byte {
	binary.BigEndian.PutUint32(, )
	return [4:]
}

func marshalUint64( []byte,  uint64) []byte {
	binary.BigEndian.PutUint64(, )
	return [8:]
}

func marshalInt( []byte,  *big.Int) []byte {
	 := 
	 = [4:]
	 := 0

	if .Sign() < 0 {
		// A negative number has to be converted to two's-complement
		// form. So we'll subtract 1 and invert. If the
		// most-significant-bit isn't set then we'll need to pad the
		// beginning with 0xff in order to keep the number negative.
		 := new(big.Int).Neg()
		.Sub(, bigOne)
		 := .Bytes()
		for  := range  {
			[] ^= 0xff
		}
		if len() == 0 || [0]&0x80 == 0 {
			[0] = 0xff
			 = [1:]
			++
		}
		 := copy(, )
		 = [:]
		 += 
	} else if .Sign() == 0 {
		// A zero is the zero length string
	} else {
		 := .Bytes()
		if len() > 0 && [0]&0x80 != 0 {
			// We'll have to pad this with a 0x00 in order to
			// stop it looking like a negative number.
			[0] = 0
			 = [1:]
			++
		}
		 := copy(, )
		 = [:]
		 += 
	}

	[0] = byte( >> 24)
	[1] = byte( >> 16)
	[2] = byte( >> 8)
	[3] = byte()
	return 
}

func writeInt( io.Writer,  *big.Int) {
	 := intLength()
	 := make([]byte, )
	marshalInt(, )
	.Write()
}

func writeString( io.Writer,  []byte) {
	var  [4]byte
	[0] = byte(len() >> 24)
	[1] = byte(len() >> 16)
	[2] = byte(len() >> 8)
	[3] = byte(len())
	.Write([:])
	.Write()
}

func stringLength( int) int {
	return 4 + 
}

func marshalString( []byte,  []byte) []byte {
	[0] = byte(len() >> 24)
	[1] = byte(len() >> 16)
	[2] = byte(len() >> 8)
	[3] = byte(len())
	 = [4:]
	copy(, )
	return [len():]
}

var bigIntType = reflect.TypeOf((*big.Int)(nil))

// Decode a packet into its corresponding message.
func decode( []byte) (interface{}, error) {
	var  interface{}
	switch [0] {
	case msgDisconnect:
		 = new(disconnectMsg)
	case msgServiceRequest:
		 = new(serviceRequestMsg)
	case msgServiceAccept:
		 = new(serviceAcceptMsg)
	case msgExtInfo:
		 = new(extInfoMsg)
	case msgKexInit:
		 = new(kexInitMsg)
	case msgKexDHInit:
		 = new(kexDHInitMsg)
	case msgKexDHReply:
		 = new(kexDHReplyMsg)
	case msgUserAuthRequest:
		 = new(userAuthRequestMsg)
	case msgUserAuthSuccess:
		return new(userAuthSuccessMsg), nil
	case msgUserAuthFailure:
		 = new(userAuthFailureMsg)
	case msgUserAuthPubKeyOk:
		 = new(userAuthPubKeyOkMsg)
	case msgGlobalRequest:
		 = new(globalRequestMsg)
	case msgRequestSuccess:
		 = new(globalRequestSuccessMsg)
	case msgRequestFailure:
		 = new(globalRequestFailureMsg)
	case msgChannelOpen:
		 = new(channelOpenMsg)
	case msgChannelData:
		 = new(channelDataMsg)
	case msgChannelOpenConfirm:
		 = new(channelOpenConfirmMsg)
	case msgChannelOpenFailure:
		 = new(channelOpenFailureMsg)
	case msgChannelWindowAdjust:
		 = new(windowAdjustMsg)
	case msgChannelEOF:
		 = new(channelEOFMsg)
	case msgChannelClose:
		 = new(channelCloseMsg)
	case msgChannelRequest:
		 = new(channelRequestMsg)
	case msgChannelSuccess:
		 = new(channelRequestSuccessMsg)
	case msgChannelFailure:
		 = new(channelRequestFailureMsg)
	case msgUserAuthGSSAPIToken:
		 = new(userAuthGSSAPIToken)
	case msgUserAuthGSSAPIMIC:
		 = new(userAuthGSSAPIMIC)
	case msgUserAuthGSSAPIErrTok:
		 = new(userAuthGSSAPIErrTok)
	case msgUserAuthGSSAPIError:
		 = new(userAuthGSSAPIError)
	default:
		return nil, unexpectedMessageError(0, [0])
	}
	if  := Unmarshal(, );  != nil {
		return nil, 
	}
	return , nil
}

var packetTypeNames = map[byte]string{
	msgDisconnect:          "disconnectMsg",
	msgServiceRequest:      "serviceRequestMsg",
	msgServiceAccept:       "serviceAcceptMsg",
	msgExtInfo:             "extInfoMsg",
	msgKexInit:             "kexInitMsg",
	msgKexDHInit:           "kexDHInitMsg",
	msgKexDHReply:          "kexDHReplyMsg",
	msgUserAuthRequest:     "userAuthRequestMsg",
	msgUserAuthSuccess:     "userAuthSuccessMsg",
	msgUserAuthFailure:     "userAuthFailureMsg",
	msgUserAuthPubKeyOk:    "userAuthPubKeyOkMsg",
	msgGlobalRequest:       "globalRequestMsg",
	msgRequestSuccess:      "globalRequestSuccessMsg",
	msgRequestFailure:      "globalRequestFailureMsg",
	msgChannelOpen:         "channelOpenMsg",
	msgChannelData:         "channelDataMsg",
	msgChannelOpenConfirm:  "channelOpenConfirmMsg",
	msgChannelOpenFailure:  "channelOpenFailureMsg",
	msgChannelWindowAdjust: "windowAdjustMsg",
	msgChannelEOF:          "channelEOFMsg",
	msgChannelClose:        "channelCloseMsg",
	msgChannelRequest:      "channelRequestMsg",
	msgChannelSuccess:      "channelRequestSuccessMsg",
	msgChannelFailure:      "channelRequestFailureMsg",
}