1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssh
6
7import (
8	"bytes"
9	"encoding/binary"
10	"errors"
11	"fmt"
12	"io"
13	"math/big"
14	"reflect"
15	"strconv"
16	"strings"
17)
18
19// These are SSH message type numbers. They are scattered around several
20// documents but many were taken from [SSH-PARAMETERS].
21const (
22	msgIgnore        = 2
23	msgUnimplemented = 3
24	msgDebug         = 4
25	msgNewKeys       = 21
26)
27
28// SSH messages:
29//
30// These structures mirror the wire format of the corresponding SSH messages.
31// They are marshaled using reflection with the marshal and unmarshal functions
32// in this file. The only wrinkle is that a final member of type []byte with a
33// ssh tag of "rest" receives the remainder of a packet when unmarshaling.
34
35// See RFC 4253, section 11.1.
36const msgDisconnect = 1
37
38// disconnectMsg is the message that signals a disconnect. It is also
39// the error type returned from mux.Wait()
40type disconnectMsg struct {
41	Reason   uint32 `sshtype:"1"`
42	Message  string
43	Language string
44}
45
46func (d *disconnectMsg) Error() string {
47	return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
48}
49
50// See RFC 4253, section 7.1.
51const msgKexInit = 20
52
53type kexInitMsg struct {
54	Cookie                  [16]byte `sshtype:"20"`
55	KexAlgos                []string
56	ServerHostKeyAlgos      []string
57	CiphersClientServer     []string
58	CiphersServerClient     []string
59	MACsClientServer        []string
60	MACsServerClient        []string
61	CompressionClientServer []string
62	CompressionServerClient []string
63	LanguagesClientServer   []string
64	LanguagesServerClient   []string
65	FirstKexFollows         bool
66	Reserved                uint32
67}
68
69// See RFC 4253, section 8.
70
71// Diffie-Helman
72const msgKexDHInit = 30
73
74type kexDHInitMsg struct {
75	X *big.Int `sshtype:"30"`
76}
77
78const msgKexECDHInit = 30
79
80type kexECDHInitMsg struct {
81	ClientPubKey []byte `sshtype:"30"`
82}
83
84const msgKexECDHReply = 31
85
86type kexECDHReplyMsg struct {
87	HostKey         []byte `sshtype:"31"`
88	EphemeralPubKey []byte
89	Signature       []byte
90}
91
92const msgKexDHReply = 31
93
94type kexDHReplyMsg struct {
95	HostKey   []byte `sshtype:"31"`
96	Y         *big.Int
97	Signature []byte
98}
99
100// See RFC 4419, section 5.
101const msgKexDHGexGroup = 31
102
103type kexDHGexGroupMsg struct {
104	P *big.Int `sshtype:"31"`
105	G *big.Int
106}
107
108const msgKexDHGexInit = 32
109
110type kexDHGexInitMsg struct {
111	X *big.Int `sshtype:"32"`
112}
113
114const msgKexDHGexReply = 33
115
116type kexDHGexReplyMsg struct {
117	HostKey   []byte `sshtype:"33"`
118	Y         *big.Int
119	Signature []byte
120}
121
122const msgKexDHGexRequest = 34
123
124type kexDHGexRequestMsg struct {
125	MinBits      uint32 `sshtype:"34"`
126	PreferedBits uint32
127	MaxBits      uint32
128}
129
130// See RFC 4253, section 10.
131const msgServiceRequest = 5
132
133type serviceRequestMsg struct {
134	Service string `sshtype:"5"`
135}
136
137// See RFC 4253, section 10.
138const msgServiceAccept = 6
139
140type serviceAcceptMsg struct {
141	Service string `sshtype:"6"`
142}
143
144// See RFC 4252, section 5.
145const msgUserAuthRequest = 50
146
147type userAuthRequestMsg struct {
148	User    string `sshtype:"50"`
149	Service string
150	Method  string
151	Payload []byte `ssh:"rest"`
152}
153
154// Used for debug printouts of packets.
155type userAuthSuccessMsg struct {
156}
157
158// See RFC 4252, section 5.1
159const msgUserAuthFailure = 51
160
161type userAuthFailureMsg struct {
162	Methods        []string `sshtype:"51"`
163	PartialSuccess bool
164}
165
166// See RFC 4252, section 5.1
167const msgUserAuthSuccess = 52
168
169// See RFC 4252, section 5.4
170const msgUserAuthBanner = 53
171
172type userAuthBannerMsg struct {
173	Message string `sshtype:"53"`
174	// unused, but required to allow message parsing
175	Language string
176}
177
178// See RFC 4256, section 3.2
179const msgUserAuthInfoRequest = 60
180const msgUserAuthInfoResponse = 61
181
182type userAuthInfoRequestMsg struct {
183	User               string `sshtype:"60"`
184	Instruction        string
185	DeprecatedLanguage string
186	NumPrompts         uint32
187	Prompts            []byte `ssh:"rest"`
188}
189
190// See RFC 4254, section 5.1.
191const msgChannelOpen = 90
192
193type channelOpenMsg struct {
194	ChanType         string `sshtype:"90"`
195	PeersID          uint32
196	PeersWindow      uint32
197	MaxPacketSize    uint32
198	TypeSpecificData []byte `ssh:"rest"`
199}
200
201const msgChannelExtendedData = 95
202const msgChannelData = 94
203
204// Used for debug print outs of packets.
205type channelDataMsg struct {
206	PeersID uint32 `sshtype:"94"`
207	Length  uint32
208	Rest    []byte `ssh:"rest"`
209}
210
211// See RFC 4254, section 5.1.
212const msgChannelOpenConfirm = 91
213
214type channelOpenConfirmMsg struct {
215	PeersID          uint32 `sshtype:"91"`
216	MyID             uint32
217	MyWindow         uint32
218	MaxPacketSize    uint32
219	TypeSpecificData []byte `ssh:"rest"`
220}
221
222// See RFC 4254, section 5.1.
223const msgChannelOpenFailure = 92
224
225type channelOpenFailureMsg struct {
226	PeersID  uint32 `sshtype:"92"`
227	Reason   RejectionReason
228	Message  string
229	Language string
230}
231
232const msgChannelRequest = 98
233
234type channelRequestMsg struct {
235	PeersID             uint32 `sshtype:"98"`
236	Request             string
237	WantReply           bool
238	RequestSpecificData []byte `ssh:"rest"`
239}
240
241// See RFC 4254, section 5.4.
242const msgChannelSuccess = 99
243
244type channelRequestSuccessMsg struct {
245	PeersID uint32 `sshtype:"99"`
246}
247
248// See RFC 4254, section 5.4.
249const msgChannelFailure = 100
250
251type channelRequestFailureMsg struct {
252	PeersID uint32 `sshtype:"100"`
253}
254
255// See RFC 4254, section 5.3
256const msgChannelClose = 97
257
258type channelCloseMsg struct {
259	PeersID uint32 `sshtype:"97"`
260}
261
262// See RFC 4254, section 5.3
263const msgChannelEOF = 96
264
265type channelEOFMsg struct {
266	PeersID uint32 `sshtype:"96"`
267}
268
269// See RFC 4254, section 4
270const msgGlobalRequest = 80
271
272type globalRequestMsg struct {
273	Type      string `sshtype:"80"`
274	WantReply bool
275	Data      []byte `ssh:"rest"`
276}
277
278// See RFC 4254, section 4
279const msgRequestSuccess = 81
280
281type globalRequestSuccessMsg struct {
282	Data []byte `ssh:"rest" sshtype:"81"`
283}
284
285// See RFC 4254, section 4
286const msgRequestFailure = 82
287
288type globalRequestFailureMsg struct {
289	Data []byte `ssh:"rest" sshtype:"82"`
290}
291
292// See RFC 4254, section 5.2
293const msgChannelWindowAdjust = 93
294
295type windowAdjustMsg struct {
296	PeersID         uint32 `sshtype:"93"`
297	AdditionalBytes uint32
298}
299
300// See RFC 4252, section 7
301const msgUserAuthPubKeyOk = 60
302
303type userAuthPubKeyOkMsg struct {
304	Algo   string `sshtype:"60"`
305	PubKey []byte
306}
307
308// See RFC 4462, section 3
309const msgUserAuthGSSAPIResponse = 60
310
311type userAuthGSSAPIResponse struct {
312	SupportMech []byte `sshtype:"60"`
313}
314
315const msgUserAuthGSSAPIToken = 61
316
317type userAuthGSSAPIToken struct {
318	Token []byte `sshtype:"61"`
319}
320
321const msgUserAuthGSSAPIMIC = 66
322
323type userAuthGSSAPIMIC struct {
324	MIC []byte `sshtype:"66"`
325}
326
327// See RFC 4462, section 3.9
328const msgUserAuthGSSAPIErrTok = 64
329
330type userAuthGSSAPIErrTok struct {
331	ErrorToken []byte `sshtype:"64"`
332}
333
334// See RFC 4462, section 3.8
335const msgUserAuthGSSAPIError = 65
336
337type userAuthGSSAPIError struct {
338	MajorStatus uint32 `sshtype:"65"`
339	MinorStatus uint32
340	Message     string
341	LanguageTag string
342}
343
344// typeTags returns the possible type bytes for the given reflect.Type, which
345// should be a struct. The possible values are separated by a '|' character.
346func typeTags(structType reflect.Type) (tags []byte) {
347	tagStr := structType.Field(0).Tag.Get("sshtype")
348
349	for _, tag := range strings.Split(tagStr, "|") {
350		i, err := strconv.Atoi(tag)
351		if err == nil {
352			tags = append(tags, byte(i))
353		}
354	}
355
356	return tags
357}
358
359func fieldError(t reflect.Type, field int, problem string) error {
360	if problem != "" {
361		problem = ": " + problem
362	}
363	return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
364}
365
366var errShortRead = errors.New("ssh: short read")
367
368// Unmarshal parses data in SSH wire format into a structure. The out
369// argument should be a pointer to struct. If the first member of the
370// struct has the "sshtype" tag set to a '|'-separated set of numbers
371// in decimal, the packet must start with one of those numbers. In
372// case of error, Unmarshal returns a ParseError or
373// UnexpectedMessageError.
374func Unmarshal(data []byte, out interface{}) error {
375	v := reflect.ValueOf(out).Elem()
376	structType := v.Type()
377	expectedTypes := typeTags(structType)
378
379	var expectedType byte
380	if len(expectedTypes) > 0 {
381		expectedType = expectedTypes[0]
382	}
383
384	if len(data) == 0 {
385		return parseError(expectedType)
386	}
387
388	if len(expectedTypes) > 0 {
389		goodType := false
390		for _, e := range expectedTypes {
391			if e > 0 && data[0] == e {
392				goodType = true
393				break
394			}
395		}
396		if !goodType {
397			return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
398		}
399		data = data[1:]
400	}
401
402	var ok bool
403	for i := 0; i < v.NumField(); i++ {
404		field := v.Field(i)
405		t := field.Type()
406		switch t.Kind() {
407		case reflect.Bool:
408			if len(data) < 1 {
409				return errShortRead
410			}
411			field.SetBool(data[0] != 0)
412			data = data[1:]
413		case reflect.Array:
414			if t.Elem().Kind() != reflect.Uint8 {
415				return fieldError(structType, i, "array of unsupported type")
416			}
417			if len(data) < t.Len() {
418				return errShortRead
419			}
420			for j, n := 0, t.Len(); j < n; j++ {
421				field.Index(j).Set(reflect.ValueOf(data[j]))
422			}
423			data = data[t.Len():]
424		case reflect.Uint64:
425			var u64 uint64
426			if u64, data, ok = parseUint64(data); !ok {
427				return errShortRead
428			}
429			field.SetUint(u64)
430		case reflect.Uint32:
431			var u32 uint32
432			if u32, data, ok = parseUint32(data); !ok {
433				return errShortRead
434			}
435			field.SetUint(uint64(u32))
436		case reflect.Uint8:
437			if len(data) < 1 {
438				return errShortRead
439			}
440			field.SetUint(uint64(data[0]))
441			data = data[1:]
442		case reflect.String:
443			var s []byte
444			if s, data, ok = parseString(data); !ok {
445				return fieldError(structType, i, "")
446			}
447			field.SetString(string(s))
448		case reflect.Slice:
449			switch t.Elem().Kind() {
450			case reflect.Uint8:
451				if structType.Field(i).Tag.Get("ssh") == "rest" {
452					field.Set(reflect.ValueOf(data))
453					data = nil
454				} else {
455					var s []byte
456					if s, data, ok = parseString(data); !ok {
457						return errShortRead
458					}
459					field.Set(reflect.ValueOf(s))
460				}
461			case reflect.String:
462				var nl []string
463				if nl, data, ok = parseNameList(data); !ok {
464					return errShortRead
465				}
466				field.Set(reflect.ValueOf(nl))
467			default:
468				return fieldError(structType, i, "slice of unsupported type")
469			}
470		case reflect.Ptr:
471			if t == bigIntType {
472				var n *big.Int
473				if n, data, ok = parseInt(data); !ok {
474					return errShortRead
475				}
476				field.Set(reflect.ValueOf(n))
477			} else {
478				return fieldError(structType, i, "pointer to unsupported type")
479			}
480		default:
481			return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
482		}
483	}
484
485	if len(data) != 0 {
486		return parseError(expectedType)
487	}
488
489	return nil
490}
491
492// Marshal serializes the message in msg to SSH wire format.  The msg
493// argument should be a struct or pointer to struct. If the first
494// member has the "sshtype" tag set to a number in decimal, that
495// number is prepended to the result. If the last of member has the
496// "ssh" tag set to "rest", its contents are appended to the output.
497func Marshal(msg interface{}) []byte {
498	out := make([]byte, 0, 64)
499	return marshalStruct(out, msg)
500}
501
502func marshalStruct(out []byte, msg interface{}) []byte {
503	v := reflect.Indirect(reflect.ValueOf(msg))
504	msgTypes := typeTags(v.Type())
505	if len(msgTypes) > 0 {
506		out = append(out, msgTypes[0])
507	}
508
509	for i, n := 0, v.NumField(); i < n; i++ {
510		field := v.Field(i)
511		switch t := field.Type(); t.Kind() {
512		case reflect.Bool:
513			var v uint8
514			if field.Bool() {
515				v = 1
516			}
517			out = append(out, v)
518		case reflect.Array:
519			if t.Elem().Kind() != reflect.Uint8 {
520				panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface()))
521			}
522			for j, l := 0, t.Len(); j < l; j++ {
523				out = append(out, uint8(field.Index(j).Uint()))
524			}
525		case reflect.Uint32:
526			out = appendU32(out, uint32(field.Uint()))
527		case reflect.Uint64:
528			out = appendU64(out, uint64(field.Uint()))
529		case reflect.Uint8:
530			out = append(out, uint8(field.Uint()))
531		case reflect.String:
532			s := field.String()
533			out = appendInt(out, len(s))
534			out = append(out, s...)
535		case reflect.Slice:
536			switch t.Elem().Kind() {
537			case reflect.Uint8:
538				if v.Type().Field(i).Tag.Get("ssh") != "rest" {
539					out = appendInt(out, field.Len())
540				}
541				out = append(out, field.Bytes()...)
542			case reflect.String:
543				offset := len(out)
544				out = appendU32(out, 0)
545				if n := field.Len(); n > 0 {
546					for j := 0; j < n; j++ {
547						f := field.Index(j)
548						if j != 0 {
549							out = append(out, ',')
550						}
551						out = append(out, f.String()...)
552					}
553					// overwrite length value
554					binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4))
555				}
556			default:
557				panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface()))
558			}
559		case reflect.Ptr:
560			if t == bigIntType {
561				var n *big.Int
562				nValue := reflect.ValueOf(&n)
563				nValue.Elem().Set(field)
564				needed := intLength(n)
565				oldLength := len(out)
566
567				if cap(out)-len(out) < needed {
568					newOut := make([]byte, len(out), 2*(len(out)+needed))
569					copy(newOut, out)
570					out = newOut
571				}
572				out = out[:oldLength+needed]
573				marshalInt(out[oldLength:], n)
574			} else {
575				panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface()))
576			}
577		}
578	}
579
580	return out
581}
582
583var bigOne = big.NewInt(1)
584
585func parseString(in []byte) (out, rest []byte, ok bool) {
586	if len(in) < 4 {
587		return
588	}
589	length := binary.BigEndian.Uint32(in)
590	in = in[4:]
591	if uint32(len(in)) < length {
592		return
593	}
594	out = in[:length]
595	rest = in[length:]
596	ok = true
597	return
598}
599
600var (
601	comma         = []byte{','}
602	emptyNameList = []string{}
603)
604
605func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
606	contents, rest, ok := parseString(in)
607	if !ok {
608		return
609	}
610	if len(contents) == 0 {
611		out = emptyNameList
612		return
613	}
614	parts := bytes.Split(contents, comma)
615	out = make([]string, len(parts))
616	for i, part := range parts {
617		out[i] = string(part)
618	}
619	return
620}
621
622func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
623	contents, rest, ok := parseString(in)
624	if !ok {
625		return
626	}
627	out = new(big.Int)
628
629	if len(contents) > 0 && contents[0]&0x80 == 0x80 {
630		// This is a negative number
631		notBytes := make([]byte, len(contents))
632		for i := range notBytes {
633			notBytes[i] = ^contents[i]
634		}
635		out.SetBytes(notBytes)
636		out.Add(out, bigOne)
637		out.Neg(out)
638	} else {
639		// Positive number
640		out.SetBytes(contents)
641	}
642	ok = true
643	return
644}
645
646func parseUint32(in []byte) (uint32, []byte, bool) {
647	if len(in) < 4 {
648		return 0, nil, false
649	}
650	return binary.BigEndian.Uint32(in), in[4:], true
651}
652
653func parseUint64(in []byte) (uint64, []byte, bool) {
654	if len(in) < 8 {
655		return 0, nil, false
656	}
657	return binary.BigEndian.Uint64(in), in[8:], true
658}
659
660func intLength(n *big.Int) int {
661	length := 4 /* length bytes */
662	if n.Sign() < 0 {
663		nMinus1 := new(big.Int).Neg(n)
664		nMinus1.Sub(nMinus1, bigOne)
665		bitLen := nMinus1.BitLen()
666		if bitLen%8 == 0 {
667			// The number will need 0xff padding
668			length++
669		}
670		length += (bitLen + 7) / 8
671	} else if n.Sign() == 0 {
672		// A zero is the zero length string
673	} else {
674		bitLen := n.BitLen()
675		if bitLen%8 == 0 {
676			// The number will need 0x00 padding
677			length++
678		}
679		length += (bitLen + 7) / 8
680	}
681
682	return length
683}
684
685func marshalUint32(to []byte, n uint32) []byte {
686	binary.BigEndian.PutUint32(to, n)
687	return to[4:]
688}
689
690func marshalUint64(to []byte, n uint64) []byte {
691	binary.BigEndian.PutUint64(to, n)
692	return to[8:]
693}
694
695func marshalInt(to []byte, n *big.Int) []byte {
696	lengthBytes := to
697	to = to[4:]
698	length := 0
699
700	if n.Sign() < 0 {
701		// A negative number has to be converted to two's-complement
702		// form. So we'll subtract 1 and invert. If the
703		// most-significant-bit isn't set then we'll need to pad the
704		// beginning with 0xff in order to keep the number negative.
705		nMinus1 := new(big.Int).Neg(n)
706		nMinus1.Sub(nMinus1, bigOne)
707		bytes := nMinus1.Bytes()
708		for i := range bytes {
709			bytes[i] ^= 0xff
710		}
711		if len(bytes) == 0 || bytes[0]&0x80 == 0 {
712			to[0] = 0xff
713			to = to[1:]
714			length++
715		}
716		nBytes := copy(to, bytes)
717		to = to[nBytes:]
718		length += nBytes
719	} else if n.Sign() == 0 {
720		// A zero is the zero length string
721	} else {
722		bytes := n.Bytes()
723		if len(bytes) > 0 && bytes[0]&0x80 != 0 {
724			// We'll have to pad this with a 0x00 in order to
725			// stop it looking like a negative number.
726			to[0] = 0
727			to = to[1:]
728			length++
729		}
730		nBytes := copy(to, bytes)
731		to = to[nBytes:]
732		length += nBytes
733	}
734
735	lengthBytes[0] = byte(length >> 24)
736	lengthBytes[1] = byte(length >> 16)
737	lengthBytes[2] = byte(length >> 8)
738	lengthBytes[3] = byte(length)
739	return to
740}
741
742func writeInt(w io.Writer, n *big.Int) {
743	length := intLength(n)
744	buf := make([]byte, length)
745	marshalInt(buf, n)
746	w.Write(buf)
747}
748
749func writeString(w io.Writer, s []byte) {
750	var lengthBytes [4]byte
751	lengthBytes[0] = byte(len(s) >> 24)
752	lengthBytes[1] = byte(len(s) >> 16)
753	lengthBytes[2] = byte(len(s) >> 8)
754	lengthBytes[3] = byte(len(s))
755	w.Write(lengthBytes[:])
756	w.Write(s)
757}
758
759func stringLength(n int) int {
760	return 4 + n
761}
762
763func marshalString(to []byte, s []byte) []byte {
764	to[0] = byte(len(s) >> 24)
765	to[1] = byte(len(s) >> 16)
766	to[2] = byte(len(s) >> 8)
767	to[3] = byte(len(s))
768	to = to[4:]
769	copy(to, s)
770	return to[len(s):]
771}
772
773var bigIntType = reflect.TypeOf((*big.Int)(nil))
774
775// Decode a packet into its corresponding message.
776func decode(packet []byte) (interface{}, error) {
777	var msg interface{}
778	switch packet[0] {
779	case msgDisconnect:
780		msg = new(disconnectMsg)
781	case msgServiceRequest:
782		msg = new(serviceRequestMsg)
783	case msgServiceAccept:
784		msg = new(serviceAcceptMsg)
785	case msgKexInit:
786		msg = new(kexInitMsg)
787	case msgKexDHInit:
788		msg = new(kexDHInitMsg)
789	case msgKexDHReply:
790		msg = new(kexDHReplyMsg)
791	case msgUserAuthRequest:
792		msg = new(userAuthRequestMsg)
793	case msgUserAuthSuccess:
794		return new(userAuthSuccessMsg), nil
795	case msgUserAuthFailure:
796		msg = new(userAuthFailureMsg)
797	case msgUserAuthPubKeyOk:
798		msg = new(userAuthPubKeyOkMsg)
799	case msgGlobalRequest:
800		msg = new(globalRequestMsg)
801	case msgRequestSuccess:
802		msg = new(globalRequestSuccessMsg)
803	case msgRequestFailure:
804		msg = new(globalRequestFailureMsg)
805	case msgChannelOpen:
806		msg = new(channelOpenMsg)
807	case msgChannelData:
808		msg = new(channelDataMsg)
809	case msgChannelOpenConfirm:
810		msg = new(channelOpenConfirmMsg)
811	case msgChannelOpenFailure:
812		msg = new(channelOpenFailureMsg)
813	case msgChannelWindowAdjust:
814		msg = new(windowAdjustMsg)
815	case msgChannelEOF:
816		msg = new(channelEOFMsg)
817	case msgChannelClose:
818		msg = new(channelCloseMsg)
819	case msgChannelRequest:
820		msg = new(channelRequestMsg)
821	case msgChannelSuccess:
822		msg = new(channelRequestSuccessMsg)
823	case msgChannelFailure:
824		msg = new(channelRequestFailureMsg)
825	case msgUserAuthGSSAPIToken:
826		msg = new(userAuthGSSAPIToken)
827	case msgUserAuthGSSAPIMIC:
828		msg = new(userAuthGSSAPIMIC)
829	case msgUserAuthGSSAPIErrTok:
830		msg = new(userAuthGSSAPIErrTok)
831	case msgUserAuthGSSAPIError:
832		msg = new(userAuthGSSAPIError)
833	default:
834		return nil, unexpectedMessageError(0, packet[0])
835	}
836	if err := Unmarshal(packet, msg); err != nil {
837		return nil, err
838	}
839	return msg, nil
840}
841
842var packetTypeNames = map[byte]string{
843	msgDisconnect:          "disconnectMsg",
844	msgServiceRequest:      "serviceRequestMsg",
845	msgServiceAccept:       "serviceAcceptMsg",
846	msgKexInit:             "kexInitMsg",
847	msgKexDHInit:           "kexDHInitMsg",
848	msgKexDHReply:          "kexDHReplyMsg",
849	msgUserAuthRequest:     "userAuthRequestMsg",
850	msgUserAuthSuccess:     "userAuthSuccessMsg",
851	msgUserAuthFailure:     "userAuthFailureMsg",
852	msgUserAuthPubKeyOk:    "userAuthPubKeyOkMsg",
853	msgGlobalRequest:       "globalRequestMsg",
854	msgRequestSuccess:      "globalRequestSuccessMsg",
855	msgRequestFailure:      "globalRequestFailureMsg",
856	msgChannelOpen:         "channelOpenMsg",
857	msgChannelData:         "channelDataMsg",
858	msgChannelOpenConfirm:  "channelOpenConfirmMsg",
859	msgChannelOpenFailure:  "channelOpenFailureMsg",
860	msgChannelWindowAdjust: "windowAdjustMsg",
861	msgChannelEOF:          "channelEOFMsg",
862	msgChannelClose:        "channelCloseMsg",
863	msgChannelRequest:      "channelRequestMsg",
864	msgChannelSuccess:      "channelRequestSuccessMsg",
865	msgChannelFailure:      "channelRequestFailureMsg",
866}
867