mirror of
https://github.com/golang/go
synced 2024-11-21 19:14: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
|
TARG=exp/ssh
|
||||||
GOFILES=\
|
GOFILES=\
|
||||||
|
channel.go\
|
||||||
common.go\
|
common.go\
|
||||||
messages.go\
|
messages.go\
|
||||||
server.go\
|
|
||||||
transport.go\
|
transport.go\
|
||||||
channel.go\
|
server.go\
|
||||||
server_shell.go\
|
server_shell.go\
|
||||||
|
|
||||||
include ../../../Make.pkg
|
include ../../../Make.pkg
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
package ssh
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are string constants in the SSH protocol.
|
// These are string constants in the SSH protocol.
|
||||||
@ -19,6 +21,32 @@ const (
|
|||||||
serviceSSH = "ssh-connection"
|
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
|
// UnexpectedMessageError results when the SSH message that we received didn't
|
||||||
// match what we wanted.
|
// match what we wanted.
|
||||||
type UnexpectedMessageError struct {
|
type UnexpectedMessageError struct {
|
||||||
@ -38,6 +66,11 @@ func (p ParseError) String() string {
|
|||||||
return "ssh: parse error in message type " + strconv.Itoa(int(p.msgType))
|
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) {
|
func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
|
||||||
for _, clientAlgo := range clientAlgos {
|
for _, clientAlgo := range clientAlgos {
|
||||||
for _, serverAlgo := range serverAlgos {
|
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
|
// 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.
|
// 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.
|
// See RFC 4253, section 7.1.
|
||||||
type kexInitMsg struct {
|
type kexInitMsg struct {
|
||||||
Cookie [16]byte
|
Cookie [16]byte
|
||||||
@ -137,6 +144,12 @@ type channelOpenFailureMsg struct {
|
|||||||
Language string
|
Language string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See RFC 4254, section 5.2.
|
||||||
|
type channelData struct {
|
||||||
|
PeersId uint32
|
||||||
|
Payload []byte "rest"
|
||||||
|
}
|
||||||
|
|
||||||
type channelRequestMsg struct {
|
type channelRequestMsg struct {
|
||||||
PeersId uint32
|
PeersId uint32
|
||||||
Request string
|
Request string
|
||||||
@ -555,3 +568,60 @@ func marshalString(to []byte, s []byte) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var bigIntType = reflect.TypeOf((*big.Int)(nil))
|
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 (
|
import (
|
||||||
"big"
|
"big"
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -19,12 +18,6 @@ import (
|
|||||||
"sync"
|
"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.
|
// Server represents an SSH server. A Server may have several ServerConnections.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
rsa *rsa.PrivateKey
|
rsa *rsa.PrivateKey
|
||||||
@ -146,31 +139,6 @@ type ServerConnection struct {
|
|||||||
cachedPubKeys []cachedPubKey
|
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
|
// kexDH performs Diffie-Hellman key agreement on a ServerConnection. The
|
||||||
// returned values are given the same names as in RFC 4253, section 8.
|
// 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) {
|
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.
|
// Handshake performs an SSH transport and client authentication on the given ServerConnection.
|
||||||
func (s *ServerConnection) Handshake(conn net.Conn) os.Error {
|
func (s *ServerConnection) Handshake(conn net.Conn) os.Error {
|
||||||
var magics handshakeMagics
|
var magics handshakeMagics
|
||||||
s.transport = &transport{
|
s.transport = newTransport(conn)
|
||||||
reader: reader{
|
|
||||||
Reader: bufio.NewReader(conn),
|
|
||||||
},
|
|
||||||
writer: writer{
|
|
||||||
Writer: bufio.NewWriter(conn),
|
|
||||||
rand: rand.Reader,
|
|
||||||
},
|
|
||||||
Close: func() os.Error {
|
|
||||||
return conn.Close()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := conn.Write(serverVersion); err != nil {
|
if _, err := conn.Write(serverVersion); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -612,19 +569,14 @@ func (s *ServerConnection) Accept() (Channel, os.Error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch packet[0] {
|
switch msg := decode(packet).(type) {
|
||||||
case msgChannelOpen:
|
case *channelOpenMsg:
|
||||||
var chanOpen channelOpenMsg
|
|
||||||
if err := unmarshal(&chanOpen, packet, msgChannelOpen); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c := new(channel)
|
c := new(channel)
|
||||||
c.chanType = chanOpen.ChanType
|
c.chanType = msg.ChanType
|
||||||
c.theirId = chanOpen.PeersId
|
c.theirId = msg.PeersId
|
||||||
c.theirWindow = chanOpen.PeersWindow
|
c.theirWindow = msg.PeersWindow
|
||||||
c.maxPacketSize = chanOpen.MaxPacketSize
|
c.maxPacketSize = msg.MaxPacketSize
|
||||||
c.extraData = chanOpen.TypeSpecificData
|
c.extraData = msg.TypeSpecificData
|
||||||
c.myWindow = defaultWindowSize
|
c.myWindow = defaultWindowSize
|
||||||
c.serverConn = s
|
c.serverConn = s
|
||||||
c.cond = sync.NewCond(&c.lock)
|
c.cond = sync.NewCond(&c.lock)
|
||||||
@ -637,74 +589,53 @@ func (s *ServerConnection) Accept() (Channel, os.Error) {
|
|||||||
s.lock.Unlock()
|
s.lock.Unlock()
|
||||||
return c, nil
|
return c, nil
|
||||||
|
|
||||||
case msgChannelRequest:
|
case *channelRequestMsg:
|
||||||
var chanRequest channelRequestMsg
|
|
||||||
if err := unmarshal(&chanRequest, packet, msgChannelRequest); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
c, ok := s.channels[chanRequest.PeersId]
|
c, ok := s.channels[msg.PeersId]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.handlePacket(&chanRequest)
|
c.handlePacket(msg)
|
||||||
s.lock.Unlock()
|
s.lock.Unlock()
|
||||||
|
|
||||||
case msgChannelData:
|
case *channelData:
|
||||||
if len(packet) < 5 {
|
|
||||||
return nil, ParseError{msgChannelData}
|
|
||||||
}
|
|
||||||
chanId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
|
|
||||||
|
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
c, ok := s.channels[chanId]
|
c, ok := s.channels[msg.PeersId]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.handleData(packet[9:])
|
c.handleData(msg.Payload)
|
||||||
s.lock.Unlock()
|
s.lock.Unlock()
|
||||||
|
|
||||||
case msgChannelEOF:
|
case *channelEOFMsg:
|
||||||
var eofMsg channelEOFMsg
|
|
||||||
if err := unmarshal(&eofMsg, packet, msgChannelEOF); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
c, ok := s.channels[eofMsg.PeersId]
|
c, ok := s.channels[msg.PeersId]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.handlePacket(&eofMsg)
|
c.handlePacket(msg)
|
||||||
s.lock.Unlock()
|
s.lock.Unlock()
|
||||||
|
|
||||||
case msgChannelClose:
|
case *channelCloseMsg:
|
||||||
var closeMsg channelCloseMsg
|
|
||||||
if err := unmarshal(&closeMsg, packet, msgChannelClose); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
c, ok := s.channels[closeMsg.PeersId]
|
c, ok := s.channels[msg.PeersId]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.handlePacket(&closeMsg)
|
c.handlePacket(msg)
|
||||||
s.lock.Unlock()
|
s.lock.Unlock()
|
||||||
|
|
||||||
case msgGlobalRequest:
|
case *globalRequestMsg:
|
||||||
var request globalRequestMsg
|
if msg.WantReply {
|
||||||
if err := unmarshal(&request, packet, msgGlobalRequest); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if request.WantReply {
|
|
||||||
if err := s.writePacket([]byte{msgRequestFailure}); err != nil {
|
if err := s.writePacket([]byte{msgRequestFailure}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case UnexpectedMessageError:
|
||||||
|
return nil, msg
|
||||||
|
case *disconnectMsg:
|
||||||
|
return nil, os.EOF
|
||||||
default:
|
default:
|
||||||
// Unknown message. Ignore.
|
// Unknown message. Ignore.
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,13 @@ import (
|
|||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
|
"crypto/rand"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -29,7 +32,8 @@ type transport struct {
|
|||||||
macAlgo string
|
macAlgo string
|
||||||
compressionAlgo string
|
compressionAlgo string
|
||||||
|
|
||||||
Close func() os.Error
|
Close func() os.Error
|
||||||
|
RemoteAddr func() net.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// reader represents the incoming connection state.
|
// reader represents the incoming connection state.
|
||||||
@ -40,6 +44,7 @@ type reader struct {
|
|||||||
|
|
||||||
// writer represnts the outgoing connection state.
|
// writer represnts the outgoing connection state.
|
||||||
type writer struct {
|
type writer struct {
|
||||||
|
*sync.Mutex // protects writer.Writer from concurrent writes
|
||||||
*bufio.Writer
|
*bufio.Writer
|
||||||
paddingMultiple int
|
paddingMultiple int
|
||||||
rand io.Reader
|
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.
|
// Encrypt and send a packet of data to the remote peer.
|
||||||
func (w *writer) writePacket(packet []byte) os.Error {
|
func (w *writer) writePacket(packet []byte) os.Error {
|
||||||
|
w.Mutex.Lock()
|
||||||
|
defer w.Mutex.Unlock()
|
||||||
|
|
||||||
paddingLength := paddingMultiple - (5+len(packet))%paddingMultiple
|
paddingLength := paddingMultiple - (5+len(packet))%paddingMultiple
|
||||||
if paddingLength < 4 {
|
if paddingLength < 4 {
|
||||||
paddingLength += paddingMultiple
|
paddingLength += paddingMultiple
|
||||||
@ -190,6 +198,31 @@ func (w *writer) writePacket(packet []byte) os.Error {
|
|||||||
return err
|
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 {
|
type direction struct {
|
||||||
ivTag []byte
|
ivTag []byte
|
||||||
keyTag []byte
|
keyTag []byte
|
||||||
|
Loading…
Reference in New Issue
Block a user