2018-09-30 18:02:42 -07:00
// 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 (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"math/big"
"reflect"
"strconv"
"strings"
)
// 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 ( d * disconnectMsg ) Error ( ) string {
return fmt . Sprintf ( "ssh: disconnect, reason %d: %s" , d . Reason , d . 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-Helman
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
}
2019-10-12 06:48:45 +00:00
// 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
}
2018-09-30 18:02:42 -07:00
// 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 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 {
User string ` sshtype:"60" `
Instruction string
DeprecatedLanguage 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
}
2019-10-12 06:48:45 +00:00
// 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
}
2018-09-30 18:02:42 -07:00
// 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 ( structType reflect . Type ) ( tags [ ] byte ) {
tagStr := structType . Field ( 0 ) . Tag . Get ( "sshtype" )
for _ , tag := range strings . Split ( tagStr , "|" ) {
i , err := strconv . Atoi ( tag )
if err == nil {
tags = append ( tags , byte ( i ) )
}
}
return tags
}
func fieldError ( t reflect . Type , field int , problem string ) error {
if problem != "" {
problem = ": " + problem
}
return fmt . Errorf ( "ssh: unmarshal error for field %s of type %s%s" , t . Field ( field ) . Name , t . Name ( ) , problem )
}
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 Unmarshal ( data [ ] byte , out interface { } ) error {
v := reflect . ValueOf ( out ) . Elem ( )
structType := v . Type ( )
expectedTypes := typeTags ( structType )
var expectedType byte
if len ( expectedTypes ) > 0 {
expectedType = expectedTypes [ 0 ]
}
if len ( data ) == 0 {
return parseError ( expectedType )
}
if len ( expectedTypes ) > 0 {
goodType := false
for _ , e := range expectedTypes {
if e > 0 && data [ 0 ] == e {
goodType = true
break
}
}
if ! goodType {
return fmt . Errorf ( "ssh: unexpected message type %d (expected one of %v)" , data [ 0 ] , expectedTypes )
}
data = data [ 1 : ]
}
var ok bool
for i := 0 ; i < v . NumField ( ) ; i ++ {
field := v . Field ( i )
t := field . Type ( )
switch t . Kind ( ) {
case reflect . Bool :
if len ( data ) < 1 {
return errShortRead
}
field . SetBool ( data [ 0 ] != 0 )
data = data [ 1 : ]
case reflect . Array :
if t . Elem ( ) . Kind ( ) != reflect . Uint8 {
return fieldError ( structType , i , "array of unsupported type" )
}
if len ( data ) < t . Len ( ) {
return errShortRead
}
for j , n := 0 , t . Len ( ) ; j < n ; j ++ {
field . Index ( j ) . Set ( reflect . ValueOf ( data [ j ] ) )
}
data = data [ t . Len ( ) : ]
case reflect . Uint64 :
var u64 uint64
if u64 , data , ok = parseUint64 ( data ) ; ! ok {
return errShortRead
}
field . SetUint ( u64 )
case reflect . Uint32 :
var u32 uint32
if u32 , data , ok = parseUint32 ( data ) ; ! ok {
return errShortRead
}
field . SetUint ( uint64 ( u32 ) )
case reflect . Uint8 :
if len ( data ) < 1 {
return errShortRead
}
field . SetUint ( uint64 ( data [ 0 ] ) )
data = data [ 1 : ]
case reflect . String :
var s [ ] byte
if s , data , ok = parseString ( data ) ; ! ok {
return fieldError ( structType , i , "" )
}
field . SetString ( string ( s ) )
case reflect . Slice :
switch t . Elem ( ) . Kind ( ) {
case reflect . Uint8 :
if structType . Field ( i ) . Tag . Get ( "ssh" ) == "rest" {
field . Set ( reflect . ValueOf ( data ) )
data = nil
} else {
var s [ ] byte
if s , data , ok = parseString ( data ) ; ! ok {
return errShortRead
}
field . Set ( reflect . ValueOf ( s ) )
}
case reflect . String :
var nl [ ] string
if nl , data , ok = parseNameList ( data ) ; ! ok {
return errShortRead
}
field . Set ( reflect . ValueOf ( nl ) )
default :
return fieldError ( structType , i , "slice of unsupported type" )
}
case reflect . Ptr :
if t == bigIntType {
var n * big . Int
if n , data , ok = parseInt ( data ) ; ! ok {
return errShortRead
}
field . Set ( reflect . ValueOf ( n ) )
} else {
return fieldError ( structType , i , "pointer to unsupported type" )
}
default :
return fieldError ( structType , i , fmt . Sprintf ( "unsupported type: %v" , t ) )
}
}
if len ( data ) != 0 {
return parseError ( expectedType )
}
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 Marshal ( msg interface { } ) [ ] byte {
out := make ( [ ] byte , 0 , 64 )
return marshalStruct ( out , msg )
}
func marshalStruct ( out [ ] byte , msg interface { } ) [ ] byte {
v := reflect . Indirect ( reflect . ValueOf ( msg ) )
msgTypes := typeTags ( v . Type ( ) )
if len ( msgTypes ) > 0 {
out = append ( out , msgTypes [ 0 ] )
}
for i , n := 0 , v . NumField ( ) ; i < n ; i ++ {
field := v . Field ( i )
switch t := field . Type ( ) ; t . Kind ( ) {
case reflect . Bool :
var v uint8
if field . Bool ( ) {
v = 1
}
out = append ( out , v )
case reflect . Array :
if t . Elem ( ) . Kind ( ) != reflect . Uint8 {
panic ( fmt . Sprintf ( "array of non-uint8 in field %d: %T" , i , field . Interface ( ) ) )
}
for j , l := 0 , t . Len ( ) ; j < l ; j ++ {
out = append ( out , uint8 ( field . Index ( j ) . Uint ( ) ) )
}
case reflect . Uint32 :
out = appendU32 ( out , uint32 ( field . Uint ( ) ) )
case reflect . Uint64 :
out = appendU64 ( out , uint64 ( field . Uint ( ) ) )
case reflect . Uint8 :
out = append ( out , uint8 ( field . Uint ( ) ) )
case reflect . String :
s := field . String ( )
out = appendInt ( out , len ( s ) )
out = append ( out , s ... )
case reflect . Slice :
switch t . Elem ( ) . Kind ( ) {
case reflect . Uint8 :
if v . Type ( ) . Field ( i ) . Tag . Get ( "ssh" ) != "rest" {
out = appendInt ( out , field . Len ( ) )
}
out = append ( out , field . Bytes ( ) ... )
case reflect . String :
offset := len ( out )
out = appendU32 ( out , 0 )
if n := field . Len ( ) ; n > 0 {
for j := 0 ; j < n ; j ++ {
f := field . Index ( j )
if j != 0 {
out = append ( out , ',' )
}
out = append ( out , f . String ( ) ... )
}
// overwrite length value
binary . BigEndian . PutUint32 ( out [ offset : ] , uint32 ( len ( out ) - offset - 4 ) )
}
default :
panic ( fmt . Sprintf ( "slice of unknown type in field %d: %T" , i , field . Interface ( ) ) )
}
case reflect . Ptr :
if t == bigIntType {
var n * big . Int
nValue := reflect . ValueOf ( & n )
nValue . Elem ( ) . Set ( field )
needed := intLength ( n )
oldLength := len ( out )
if cap ( out ) - len ( out ) < needed {
newOut := make ( [ ] byte , len ( out ) , 2 * ( len ( out ) + needed ) )
copy ( newOut , out )
out = newOut
}
out = out [ : oldLength + needed ]
marshalInt ( out [ oldLength : ] , n )
} else {
panic ( fmt . Sprintf ( "pointer to unknown type in field %d: %T" , i , field . Interface ( ) ) )
}
}
}
return out
}
var bigOne = big . NewInt ( 1 )
func parseString ( in [ ] byte ) ( out , rest [ ] byte , ok bool ) {
if len ( in ) < 4 {
return
}
length := binary . BigEndian . Uint32 ( in )
in = in [ 4 : ]
if uint32 ( len ( in ) ) < length {
return
}
out = in [ : length ]
rest = in [ length : ]
ok = true
return
}
var (
comma = [ ] byte { ',' }
emptyNameList = [ ] string { }
)
func parseNameList ( in [ ] byte ) ( out [ ] string , rest [ ] byte , ok bool ) {
contents , rest , ok := parseString ( in )
if ! ok {
return
}
if len ( contents ) == 0 {
out = emptyNameList
return
}
parts := bytes . Split ( contents , comma )
out = make ( [ ] string , len ( parts ) )
for i , part := range parts {
out [ i ] = string ( part )
}
return
}
func parseInt ( in [ ] byte ) ( out * big . Int , rest [ ] byte , ok bool ) {
contents , rest , ok := parseString ( in )
if ! ok {
return
}
out = new ( big . Int )
if len ( contents ) > 0 && contents [ 0 ] & 0x80 == 0x80 {
// This is a negative number
notBytes := make ( [ ] byte , len ( contents ) )
for i := range notBytes {
notBytes [ i ] = ^ contents [ i ]
}
out . SetBytes ( notBytes )
out . Add ( out , bigOne )
out . Neg ( out )
} else {
// Positive number
out . SetBytes ( contents )
}
ok = true
return
}
func parseUint32 ( in [ ] byte ) ( uint32 , [ ] byte , bool ) {
if len ( in ) < 4 {
return 0 , nil , false
}
return binary . BigEndian . Uint32 ( in ) , in [ 4 : ] , true
}
func parseUint64 ( in [ ] byte ) ( uint64 , [ ] byte , bool ) {
if len ( in ) < 8 {
return 0 , nil , false
}
return binary . BigEndian . Uint64 ( in ) , in [ 8 : ] , true
}
func intLength ( n * big . Int ) int {
length := 4 /* length bytes */
if n . Sign ( ) < 0 {
nMinus1 := new ( big . Int ) . Neg ( n )
nMinus1 . Sub ( nMinus1 , bigOne )
bitLen := nMinus1 . BitLen ( )
if bitLen % 8 == 0 {
// The number will need 0xff padding
length ++
}
length += ( bitLen + 7 ) / 8
} else if n . Sign ( ) == 0 {
// A zero is the zero length string
} else {
bitLen := n . BitLen ( )
if bitLen % 8 == 0 {
// The number will need 0x00 padding
length ++
}
length += ( bitLen + 7 ) / 8
}
return length
}
func marshalUint32 ( to [ ] byte , n uint32 ) [ ] byte {
binary . BigEndian . PutUint32 ( to , n )
return to [ 4 : ]
}
func marshalUint64 ( to [ ] byte , n uint64 ) [ ] byte {
binary . BigEndian . PutUint64 ( to , n )
return to [ 8 : ]
}
func marshalInt ( to [ ] byte , n * big . Int ) [ ] byte {
lengthBytes := to
to = to [ 4 : ]
length := 0
if n . 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.
nMinus1 := new ( big . Int ) . Neg ( n )
nMinus1 . Sub ( nMinus1 , bigOne )
bytes := nMinus1 . Bytes ( )
for i := range bytes {
bytes [ i ] ^ = 0xff
}
if len ( bytes ) == 0 || bytes [ 0 ] & 0x80 == 0 {
to [ 0 ] = 0xff
to = to [ 1 : ]
length ++
}
nBytes := copy ( to , bytes )
to = to [ nBytes : ]
length += nBytes
} else if n . Sign ( ) == 0 {
// A zero is the zero length string
} else {
bytes := n . Bytes ( )
if len ( bytes ) > 0 && bytes [ 0 ] & 0x80 != 0 {
// We'll have to pad this with a 0x00 in order to
// stop it looking like a negative number.
to [ 0 ] = 0
to = to [ 1 : ]
length ++
}
nBytes := copy ( to , bytes )
to = to [ nBytes : ]
length += nBytes
}
lengthBytes [ 0 ] = byte ( length >> 24 )
lengthBytes [ 1 ] = byte ( length >> 16 )
lengthBytes [ 2 ] = byte ( length >> 8 )
lengthBytes [ 3 ] = byte ( length )
return to
}
func writeInt ( w io . Writer , n * big . Int ) {
length := intLength ( n )
buf := make ( [ ] byte , length )
marshalInt ( buf , n )
w . Write ( buf )
}
func writeString ( w io . Writer , s [ ] byte ) {
var lengthBytes [ 4 ] byte
lengthBytes [ 0 ] = byte ( len ( s ) >> 24 )
lengthBytes [ 1 ] = byte ( len ( s ) >> 16 )
lengthBytes [ 2 ] = byte ( len ( s ) >> 8 )
lengthBytes [ 3 ] = byte ( len ( s ) )
w . Write ( lengthBytes [ : ] )
w . Write ( s )
}
func stringLength ( n int ) int {
return 4 + n
}
func marshalString ( to [ ] byte , s [ ] byte ) [ ] byte {
to [ 0 ] = byte ( len ( s ) >> 24 )
to [ 1 ] = byte ( len ( s ) >> 16 )
to [ 2 ] = byte ( len ( s ) >> 8 )
to [ 3 ] = byte ( len ( s ) )
to = to [ 4 : ]
copy ( to , s )
return to [ len ( s ) : ]
}
var bigIntType = reflect . TypeOf ( ( * big . Int ) ( nil ) )
// Decode a packet into its corresponding message.
func decode ( packet [ ] byte ) ( interface { } , error ) {
var msg interface { }
switch packet [ 0 ] {
case msgDisconnect :
msg = new ( disconnectMsg )
case msgServiceRequest :
msg = new ( serviceRequestMsg )
case msgServiceAccept :
msg = new ( serviceAcceptMsg )
case msgKexInit :
msg = new ( kexInitMsg )
case msgKexDHInit :
msg = new ( kexDHInitMsg )
case msgKexDHReply :
msg = new ( kexDHReplyMsg )
case msgUserAuthRequest :
msg = new ( userAuthRequestMsg )
case msgUserAuthSuccess :
return new ( userAuthSuccessMsg ) , nil
case msgUserAuthFailure :
msg = new ( userAuthFailureMsg )
case msgUserAuthPubKeyOk :
msg = new ( userAuthPubKeyOkMsg )
case msgGlobalRequest :
msg = new ( globalRequestMsg )
case msgRequestSuccess :
msg = new ( globalRequestSuccessMsg )
case msgRequestFailure :
msg = new ( globalRequestFailureMsg )
case msgChannelOpen :
msg = new ( channelOpenMsg )
case msgChannelData :
msg = new ( channelDataMsg )
case msgChannelOpenConfirm :
msg = new ( channelOpenConfirmMsg )
case msgChannelOpenFailure :
msg = new ( channelOpenFailureMsg )
case msgChannelWindowAdjust :
msg = new ( windowAdjustMsg )
case msgChannelEOF :
msg = new ( channelEOFMsg )
case msgChannelClose :
msg = new ( channelCloseMsg )
case msgChannelRequest :
msg = new ( channelRequestMsg )
case msgChannelSuccess :
msg = new ( channelRequestSuccessMsg )
case msgChannelFailure :
msg = new ( channelRequestFailureMsg )
2019-10-12 06:48:45 +00:00
case msgUserAuthGSSAPIToken :
msg = new ( userAuthGSSAPIToken )
case msgUserAuthGSSAPIMIC :
msg = new ( userAuthGSSAPIMIC )
case msgUserAuthGSSAPIErrTok :
msg = new ( userAuthGSSAPIErrTok )
case msgUserAuthGSSAPIError :
msg = new ( userAuthGSSAPIError )
2018-09-30 18:02:42 -07:00
default :
return nil , unexpectedMessageError ( 0 , packet [ 0 ] )
}
if err := Unmarshal ( packet , msg ) ; err != nil {
return nil , err
}
return msg , nil
}
2019-10-12 06:48:45 +00:00
var packetTypeNames = map [ byte ] string {
msgDisconnect : "disconnectMsg" ,
msgServiceRequest : "serviceRequestMsg" ,
msgServiceAccept : "serviceAcceptMsg" ,
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" ,
}