mirror of
https://github.com/golang/go
synced 2024-11-21 15:04:44 -07:00
exp/ssh: move common code to common.go
R=agl CC=golang-dev https://golang.org/cl/5132041
This commit is contained in:
parent
10bf744772
commit
aa2a31e6c4
@ -6,11 +6,11 @@ include ../../../Make.inc
|
||||
|
||||
TARG=exp/ssh
|
||||
GOFILES=\
|
||||
channel.go\
|
||||
common.go\
|
||||
messages.go\
|
||||
server.go\
|
||||
transport.go\
|
||||
channel.go\
|
||||
server_shell.go\
|
||||
server.go\
|
||||
server_shell.go\
|
||||
|
||||
include ../../../Make.pkg
|
||||
|
@ -5,7 +5,9 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"big"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// These are string constants in the SSH protocol.
|
||||
@ -19,6 +21,32 @@ const (
|
||||
serviceSSH = "ssh-connection"
|
||||
)
|
||||
|
||||
var supportedKexAlgos = []string{kexAlgoDH14SHA1}
|
||||
var supportedHostKeyAlgos = []string{hostAlgoRSA}
|
||||
var supportedCiphers = []string{cipherAES128CTR}
|
||||
var supportedMACs = []string{macSHA196}
|
||||
var supportedCompressions = []string{compressionNone}
|
||||
|
||||
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
|
||||
type dhGroup struct {
|
||||
g, p *big.Int
|
||||
}
|
||||
|
||||
// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
|
||||
// Oakley Group 14 in RFC 3526.
|
||||
var dhGroup14 *dhGroup
|
||||
|
||||
var dhGroup14Once sync.Once
|
||||
|
||||
func initDHGroup14() {
|
||||
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
|
||||
|
||||
dhGroup14 = &dhGroup{
|
||||
g: new(big.Int).SetInt64(2),
|
||||
p: p,
|
||||
}
|
||||
}
|
||||
|
||||
// UnexpectedMessageError results when the SSH message that we received didn't
|
||||
// match what we wanted.
|
||||
type UnexpectedMessageError struct {
|
||||
@ -38,6 +66,11 @@ func (p ParseError) String() string {
|
||||
return "ssh: parse error in message type " + strconv.Itoa(int(p.msgType))
|
||||
}
|
||||
|
||||
type handshakeMagics struct {
|
||||
clientVersion, serverVersion []byte
|
||||
clientKexInit, serverKexInit []byte
|
||||
}
|
||||
|
||||
func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
|
||||
for _, clientAlgo := range clientAlgos {
|
||||
for _, serverAlgo := range serverAlgos {
|
||||
|
@ -59,6 +59,13 @@ const (
|
||||
// in this file. The only wrinkle is that a final member of type []byte with a
|
||||
// tag of "rest" receives the remainder of a packet when unmarshaling.
|
||||
|
||||
// See RFC 4253, section 11.1.
|
||||
type disconnectMsg struct {
|
||||
Reason uint32
|
||||
Message string
|
||||
Language string
|
||||
}
|
||||
|
||||
// See RFC 4253, section 7.1.
|
||||
type kexInitMsg struct {
|
||||
Cookie [16]byte
|
||||
@ -137,6 +144,12 @@ type channelOpenFailureMsg struct {
|
||||
Language string
|
||||
}
|
||||
|
||||
// See RFC 4254, section 5.2.
|
||||
type channelData struct {
|
||||
PeersId uint32
|
||||
Payload []byte "rest"
|
||||
}
|
||||
|
||||
type channelRequestMsg struct {
|
||||
PeersId uint32
|
||||
Request string
|
||||
@ -555,3 +568,60 @@ func marshalString(to []byte, s []byte) []byte {
|
||||
}
|
||||
|
||||
var bigIntType = reflect.TypeOf((*big.Int)(nil))
|
||||
|
||||
// Decode a packet into it's corresponding message.
|
||||
func decode(packet []byte) interface{} {
|
||||
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 msgUserAuthFailure:
|
||||
msg = new(userAuthFailureMsg)
|
||||
case msgUserAuthPubKeyOk:
|
||||
msg = new(userAuthPubKeyOkMsg)
|
||||
case msgGlobalRequest:
|
||||
msg = new(globalRequestMsg)
|
||||
case msgRequestSuccess:
|
||||
msg = new(channelRequestSuccessMsg)
|
||||
case msgRequestFailure:
|
||||
msg = new(channelRequestFailureMsg)
|
||||
case msgChannelOpen:
|
||||
msg = new(channelOpenMsg)
|
||||
case msgChannelOpenConfirm:
|
||||
msg = new(channelOpenConfirmMsg)
|
||||
case msgChannelOpenFailure:
|
||||
msg = new(channelOpenFailureMsg)
|
||||
case msgChannelWindowAdjust:
|
||||
msg = new(windowAdjustMsg)
|
||||
case msgChannelData:
|
||||
msg = new(channelData)
|
||||
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)
|
||||
default:
|
||||
return UnexpectedMessageError{0, packet[0]}
|
||||
}
|
||||
if err := unmarshal(msg, packet, packet[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ package ssh
|
||||
|
||||
import (
|
||||
"big"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
@ -19,12 +18,6 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var supportedKexAlgos = []string{kexAlgoDH14SHA1}
|
||||
var supportedHostKeyAlgos = []string{hostAlgoRSA}
|
||||
var supportedCiphers = []string{cipherAES128CTR}
|
||||
var supportedMACs = []string{macSHA196}
|
||||
var supportedCompressions = []string{compressionNone}
|
||||
|
||||
// Server represents an SSH server. A Server may have several ServerConnections.
|
||||
type Server struct {
|
||||
rsa *rsa.PrivateKey
|
||||
@ -146,31 +139,6 @@ type ServerConnection struct {
|
||||
cachedPubKeys []cachedPubKey
|
||||
}
|
||||
|
||||
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
|
||||
type dhGroup struct {
|
||||
g, p *big.Int
|
||||
}
|
||||
|
||||
// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
|
||||
// Oakley Group 14 in RFC 3526.
|
||||
var dhGroup14 *dhGroup
|
||||
|
||||
var dhGroup14Once sync.Once
|
||||
|
||||
func initDHGroup14() {
|
||||
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
|
||||
|
||||
dhGroup14 = &dhGroup{
|
||||
g: new(big.Int).SetInt64(2),
|
||||
p: p,
|
||||
}
|
||||
}
|
||||
|
||||
type handshakeMagics struct {
|
||||
clientVersion, serverVersion []byte
|
||||
clientKexInit, serverKexInit []byte
|
||||
}
|
||||
|
||||
// kexDH performs Diffie-Hellman key agreement on a ServerConnection. The
|
||||
// returned values are given the same names as in RFC 4253, section 8.
|
||||
func (s *ServerConnection) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) (H, K []byte, err os.Error) {
|
||||
@ -292,18 +260,7 @@ func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubK
|
||||
// Handshake performs an SSH transport and client authentication on the given ServerConnection.
|
||||
func (s *ServerConnection) Handshake(conn net.Conn) os.Error {
|
||||
var magics handshakeMagics
|
||||
s.transport = &transport{
|
||||
reader: reader{
|
||||
Reader: bufio.NewReader(conn),
|
||||
},
|
||||
writer: writer{
|
||||
Writer: bufio.NewWriter(conn),
|
||||
rand: rand.Reader,
|
||||
},
|
||||
Close: func() os.Error {
|
||||
return conn.Close()
|
||||
},
|
||||
}
|
||||
s.transport = newTransport(conn)
|
||||
|
||||
if _, err := conn.Write(serverVersion); err != nil {
|
||||
return err
|
||||
@ -612,19 +569,14 @@ func (s *ServerConnection) Accept() (Channel, os.Error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch packet[0] {
|
||||
case msgChannelOpen:
|
||||
var chanOpen channelOpenMsg
|
||||
if err := unmarshal(&chanOpen, packet, msgChannelOpen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch msg := decode(packet).(type) {
|
||||
case *channelOpenMsg:
|
||||
c := new(channel)
|
||||
c.chanType = chanOpen.ChanType
|
||||
c.theirId = chanOpen.PeersId
|
||||
c.theirWindow = chanOpen.PeersWindow
|
||||
c.maxPacketSize = chanOpen.MaxPacketSize
|
||||
c.extraData = chanOpen.TypeSpecificData
|
||||
c.chanType = msg.ChanType
|
||||
c.theirId = msg.PeersId
|
||||
c.theirWindow = msg.PeersWindow
|
||||
c.maxPacketSize = msg.MaxPacketSize
|
||||
c.extraData = msg.TypeSpecificData
|
||||
c.myWindow = defaultWindowSize
|
||||
c.serverConn = s
|
||||
c.cond = sync.NewCond(&c.lock)
|
||||
@ -637,74 +589,53 @@ func (s *ServerConnection) Accept() (Channel, os.Error) {
|
||||
s.lock.Unlock()
|
||||
return c, nil
|
||||
|
||||
case msgChannelRequest:
|
||||
var chanRequest channelRequestMsg
|
||||
if err := unmarshal(&chanRequest, packet, msgChannelRequest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case *channelRequestMsg:
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[chanRequest.PeersId]
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
c.handlePacket(&chanRequest)
|
||||
c.handlePacket(msg)
|
||||
s.lock.Unlock()
|
||||
|
||||
case msgChannelData:
|
||||
if len(packet) < 5 {
|
||||
return nil, ParseError{msgChannelData}
|
||||
}
|
||||
chanId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
|
||||
|
||||
case *channelData:
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[chanId]
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
c.handleData(packet[9:])
|
||||
c.handleData(msg.Payload)
|
||||
s.lock.Unlock()
|
||||
|
||||
case msgChannelEOF:
|
||||
var eofMsg channelEOFMsg
|
||||
if err := unmarshal(&eofMsg, packet, msgChannelEOF); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case *channelEOFMsg:
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[eofMsg.PeersId]
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
c.handlePacket(&eofMsg)
|
||||
c.handlePacket(msg)
|
||||
s.lock.Unlock()
|
||||
|
||||
case msgChannelClose:
|
||||
var closeMsg channelCloseMsg
|
||||
if err := unmarshal(&closeMsg, packet, msgChannelClose); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case *channelCloseMsg:
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[closeMsg.PeersId]
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
c.handlePacket(&closeMsg)
|
||||
c.handlePacket(msg)
|
||||
s.lock.Unlock()
|
||||
|
||||
case msgGlobalRequest:
|
||||
var request globalRequestMsg
|
||||
if err := unmarshal(&request, packet, msgGlobalRequest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if request.WantReply {
|
||||
case *globalRequestMsg:
|
||||
if msg.WantReply {
|
||||
if err := s.writePacket([]byte{msgRequestFailure}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
case UnexpectedMessageError:
|
||||
return nil, msg
|
||||
case *disconnectMsg:
|
||||
return nil, os.EOF
|
||||
default:
|
||||
// Unknown message. Ignore.
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"hash"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -29,7 +32,8 @@ type transport struct {
|
||||
macAlgo string
|
||||
compressionAlgo string
|
||||
|
||||
Close func() os.Error
|
||||
Close func() os.Error
|
||||
RemoteAddr func() net.Addr
|
||||
}
|
||||
|
||||
// reader represents the incoming connection state.
|
||||
@ -40,6 +44,7 @@ type reader struct {
|
||||
|
||||
// writer represnts the outgoing connection state.
|
||||
type writer struct {
|
||||
*sync.Mutex // protects writer.Writer from concurrent writes
|
||||
*bufio.Writer
|
||||
paddingMultiple int
|
||||
rand io.Reader
|
||||
@ -126,6 +131,9 @@ func (t *transport) readPacket() ([]byte, os.Error) {
|
||||
|
||||
// Encrypt and send a packet of data to the remote peer.
|
||||
func (w *writer) writePacket(packet []byte) os.Error {
|
||||
w.Mutex.Lock()
|
||||
defer w.Mutex.Unlock()
|
||||
|
||||
paddingLength := paddingMultiple - (5+len(packet))%paddingMultiple
|
||||
if paddingLength < 4 {
|
||||
paddingLength += paddingMultiple
|
||||
@ -190,6 +198,31 @@ func (w *writer) writePacket(packet []byte) os.Error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send a message to the remote peer
|
||||
func (t *transport) sendMessage(typ uint8, msg interface{}) os.Error {
|
||||
packet := marshal(typ, msg)
|
||||
return t.writePacket(packet)
|
||||
}
|
||||
|
||||
func newTransport(conn net.Conn) *transport {
|
||||
return &transport{
|
||||
reader: reader{
|
||||
Reader: bufio.NewReader(conn),
|
||||
},
|
||||
writer: writer{
|
||||
Writer: bufio.NewWriter(conn),
|
||||
rand: rand.Reader,
|
||||
Mutex: new(sync.Mutex),
|
||||
},
|
||||
Close: func() os.Error {
|
||||
return conn.Close()
|
||||
},
|
||||
RemoteAddr: func() net.Addr {
|
||||
return conn.RemoteAddr()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type direction struct {
|
||||
ivTag []byte
|
||||
keyTag []byte
|
||||
|
Loading…
Reference in New Issue
Block a user