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.
22
type ServerConfig struct {
26
// Rand provides the source of entropy for key exchange. If Rand is
27
// nil, the cryptographic random reader in package crypto/rand will
31
// NoClientAuth is true if clients are allowed to connect without
35
// PasswordCallback, if non-nil, is called when a user attempts to
36
// authenticate using a password. It may be called concurrently from
37
// several goroutines.
38
PasswordCallback func(conn *ServerConn, user, password string) bool
40
// PublicKeyCallback, if non-nil, is called when a client attempts public
41
// key authentication. It must return true iff the given public key is
42
// valid for the given user.
43
PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byte) bool
45
// KeyboardInteractiveCallback, if non-nil, is called when
46
// keyboard-interactive authentication is selected (RFC
47
// 4256). The client object's Challenge function should be
48
// used to query the user. The callback may offer multiple
49
// Challenge rounds. To avoid information leaks, the client
50
// should be presented a challenge even if the user is
52
KeyboardInteractiveCallback func(conn *ServerConn, user string, client ClientKeyboardInteractive) bool
54
// Cryptographic-related configuration.
58
func (c *ServerConfig) rand() io.Reader {
65
// SetRSAPrivateKey sets the private key for a Server. A Server must have a
66
// private key configured in order to accept connections. The private key must
67
// be in the form of a PEM encoded, PKCS#1, RSA private key. The file "id_rsa"
68
// typically contains such a key.
69
func (s *ServerConfig) SetRSAPrivateKey(pemBytes []byte) error {
70
block, _ := pem.Decode(pemBytes)
72
return errors.New("ssh: no key found")
75
s.rsa, err = x509.ParsePKCS1PrivateKey(block.Bytes)
80
s.rsaSerialized = marshalPrivRSA(s.rsa)
84
func parseRSASig(in []byte) (sig []byte, ok bool) {
85
algo, in, ok := parseString(in)
86
if !ok || string(algo) != hostAlgoRSA {
89
sig, in, ok = parseString(in)
96
// cachedPubKey contains the results of querying whether a public key is
97
// acceptable for a user. The cache only applies to a single ServerConn.
98
type cachedPubKey struct {
104
const maxCachedPubKeys = 16
106
// A ServerConn represents an incoming connection.
107
type ServerConn struct {
111
channels map[uint32]*serverChan
114
// lock protects err and channels.
118
// cachedPubKeys contains the cache results of tests for public keys.
119
// Since SSH clients will query whether a public key is acceptable
120
// before attempting to authenticate with it, we end up with duplicate
121
// queries for public key validity.
122
cachedPubKeys []cachedPubKey
124
// User holds the successfully authenticated user name.
125
// It is empty if no authentication is used. It is populated before
126
// any authentication callback is called and not assigned to after that.
129
// ClientVersion is the client's version, populated after
130
// Handshake is called. It should not be modified.
133
// Initial H used for the session ID. Once assigned this must not change
134
// even during subsequent key exchanges.
138
// Server returns a new SSH server connection
139
// using c as the underlying transport.
140
func Server(c net.Conn, config *ServerConfig) *ServerConn {
142
transport: newTransport(c, config.rand()),
143
channels: make(map[uint32]*serverChan),
148
// kexDH performs Diffie-Hellman key agreement on a ServerConnection. The
149
// returned values are given the same names as in RFC 4253, section 8.
150
func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) (H, K []byte, err error) {
151
packet, err := s.readPacket()
155
var kexDHInit kexDHInitMsg
156
if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil {
160
y, err := rand.Int(s.config.rand(), group.p)
165
Y := new(big.Int).Exp(group.g, y, group.p)
166
kInt, err := group.diffieHellman(kexDHInit.X, y)
171
var serializedHostKey []byte
174
serializedHostKey = s.config.rsaSerialized
176
return nil, nil, errors.New("ssh: internal error")
180
writeString(h, magics.clientVersion)
181
writeString(h, magics.serverVersion)
182
writeString(h, magics.clientKexInit)
183
writeString(h, magics.serverKexInit)
184
writeString(h, serializedHostKey)
185
writeInt(h, kexDHInit.X)
187
K = make([]byte, intLength(kInt))
200
sig, err = rsa.SignPKCS1v15(s.config.rand(), s.config.rsa, hashFunc, hh)
205
return nil, nil, errors.New("ssh: internal error")
208
serializedSig := serializeSignature(hostKeyAlgo, sig)
210
kexDHReply := kexDHReplyMsg{
211
HostKey: serializedHostKey,
213
Signature: serializedSig,
215
packet = marshal(msgKexDHReply, kexDHReply)
217
err = s.writePacket(packet)
221
// serverVersion is the fixed identification string that Server will use.
222
var serverVersion = []byte("SSH-2.0-Go\r\n")
224
// Handshake performs an SSH transport and client authentication on the given ServerConn.
225
func (s *ServerConn) Handshake() (err error) {
226
if _, err = s.Write(serverVersion); err != nil {
229
if err = s.Flush(); err != nil {
233
s.ClientVersion, err = readVersion(s)
237
if err = s.clientInitHandshake(nil, nil); err != nil {
242
if packet, err = s.readPacket(); err != nil {
245
var serviceRequest serviceRequestMsg
246
if err = unmarshal(&serviceRequest, packet, msgServiceRequest); err != nil {
249
if serviceRequest.Service != serviceUserAuth {
250
return errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
252
serviceAccept := serviceAcceptMsg{
253
Service: serviceUserAuth,
255
if err = s.writePacket(marshal(msgServiceAccept, serviceAccept)); err != nil {
259
if err = s.authenticate(s.sessionId); err != nil {
265
func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexInitPacket []byte) (err error) {
266
serverKexInit := kexInitMsg{
267
KexAlgos: supportedKexAlgos,
268
ServerHostKeyAlgos: supportedHostKeyAlgos,
269
CiphersClientServer: s.config.Crypto.ciphers(),
270
CiphersServerClient: s.config.Crypto.ciphers(),
271
MACsClientServer: s.config.Crypto.macs(),
272
MACsServerClient: s.config.Crypto.macs(),
273
CompressionClientServer: supportedCompressions,
274
CompressionServerClient: supportedCompressions,
276
serverKexInitPacket := marshal(msgKexInit, serverKexInit)
278
if err = s.writePacket(serverKexInitPacket); err != nil {
282
if clientKexInitPacket == nil {
283
clientKexInit = new(kexInitMsg)
284
if clientKexInitPacket, err = s.readPacket(); err != nil {
287
if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexInit); err != nil {
292
kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(s.transport, clientKexInit, &serverKexInit)
294
return errors.New("ssh: no common algorithms")
297
if clientKexInit.FirstKexFollows && kexAlgo != clientKexInit.KexAlgos[0] {
298
// The client sent a Kex message for the wrong algorithm,
299
// which we have to ignore.
300
if _, err = s.readPacket(); err != nil {
305
var magics handshakeMagics
306
magics.serverVersion = serverVersion[:len(serverVersion)-2]
307
magics.clientVersion = s.ClientVersion
308
magics.serverKexInit = marshal(msgKexInit, serverKexInit)
309
magics.clientKexInit = clientKexInitPacket
312
var hashFunc crypto.Hash
314
case kexAlgoDH14SHA1:
315
hashFunc = crypto.SHA1
316
dhGroup14Once.Do(initDHGroup14)
317
H, K, err = s.kexDH(dhGroup14, hashFunc, &magics, hostKeyAlgo)
319
hashFunc = crypto.SHA1
320
dhGroup1Once.Do(initDHGroup1)
321
H, K, err = s.kexDH(dhGroup1, hashFunc, &magics, hostKeyAlgo)
323
err = errors.New("ssh: unexpected key exchange algorithm " + kexAlgo)
328
// sessionId must only be assigned during initial handshake.
329
if s.sessionId == nil {
335
if err = s.writePacket([]byte{msgNewKeys}); err != nil {
338
if err = s.transport.writer.setupKeys(serverKeys, K, H, s.sessionId, hashFunc); err != nil {
342
if packet, err = s.readPacket(); err != nil {
345
if packet[0] != msgNewKeys {
346
return UnexpectedMessageError{msgNewKeys, packet[0]}
348
if err = s.transport.reader.setupKeys(clientKeys, K, H, s.sessionId, hashFunc); err != nil {
355
func isAcceptableAlgo(algo string) bool {
356
return algo == hostAlgoRSA
359
// testPubKey returns true if the given public key is acceptable for the user.
360
func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
361
if s.config.PublicKeyCallback == nil || !isAcceptableAlgo(algo) {
365
for _, c := range s.cachedPubKeys {
366
if c.user == user && c.algo == algo && bytes.Equal(c.pubKey, pubKey) {
371
result := s.config.PublicKeyCallback(s, user, algo, pubKey)
372
if len(s.cachedPubKeys) < maxCachedPubKeys {
376
pubKey: make([]byte, len(pubKey)),
379
copy(c.pubKey, pubKey)
380
s.cachedPubKeys = append(s.cachedPubKeys, c)
386
func (s *ServerConn) authenticate(H []byte) error {
387
var userAuthReq userAuthRequestMsg
393
if packet, err = s.readPacket(); err != nil {
396
if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); err != nil {
400
if userAuthReq.Service != serviceSSH {
401
return errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
404
switch userAuthReq.Method {
406
if s.config.NoClientAuth {
410
if s.config.PasswordCallback == nil {
413
payload := userAuthReq.Payload
414
if len(payload) < 1 || payload[0] != 0 {
415
return ParseError{msgUserAuthRequest}
417
payload = payload[1:]
418
password, payload, ok := parseString(payload)
419
if !ok || len(payload) > 0 {
420
return ParseError{msgUserAuthRequest}
423
s.User = userAuthReq.User
424
if s.config.PasswordCallback(s, userAuthReq.User, string(password)) {
427
case "keyboard-interactive":
428
if s.config.KeyboardInteractiveCallback == nil {
432
s.User = userAuthReq.User
433
if s.config.KeyboardInteractiveCallback(s, s.User, &sshClientKeyboardInteractive{s}) {
437
if s.config.PublicKeyCallback == nil {
440
payload := userAuthReq.Payload
441
if len(payload) < 1 {
442
return ParseError{msgUserAuthRequest}
444
isQuery := payload[0] == 0
445
payload = payload[1:]
446
algoBytes, payload, ok := parseString(payload)
448
return ParseError{msgUserAuthRequest}
450
algo := string(algoBytes)
452
pubKey, payload, ok := parseString(payload)
454
return ParseError{msgUserAuthRequest}
457
// The client can query if the given public key
459
if len(payload) > 0 {
460
return ParseError{msgUserAuthRequest}
462
if s.testPubKey(userAuthReq.User, algo, pubKey) {
463
okMsg := userAuthPubKeyOkMsg{
465
PubKey: string(pubKey),
467
if err = s.writePacket(marshal(msgUserAuthPubKeyOk, okMsg)); err != nil {
470
continue userAuthLoop
473
sig, payload, ok := parseString(payload)
474
if !ok || len(payload) > 0 {
475
return ParseError{msgUserAuthRequest}
477
if !isAcceptableAlgo(algo) {
480
rsaSig, ok := parseRSASig(sig)
482
return ParseError{msgUserAuthRequest}
484
signedData := buildDataSignedForAuth(H, userAuthReq, algoBytes, pubKey)
487
hashFunc := crypto.SHA1
491
key, _, ok := parsePubKey(pubKey)
493
return ParseError{msgUserAuthRequest}
495
rsaKey, ok := key.(*rsa.PublicKey)
497
return ParseError{msgUserAuthRequest}
499
if rsa.VerifyPKCS1v15(rsaKey, hashFunc, digest, rsaSig) != nil {
500
return ParseError{msgUserAuthRequest}
503
return errors.New("ssh: isAcceptableAlgo incorrect")
505
s.User = userAuthReq.User
506
if s.testPubKey(userAuthReq.User, algo, pubKey) {
512
var failureMsg userAuthFailureMsg
513
if s.config.PasswordCallback != nil {
514
failureMsg.Methods = append(failureMsg.Methods, "password")
516
if s.config.PublicKeyCallback != nil {
517
failureMsg.Methods = append(failureMsg.Methods, "publickey")
519
if s.config.KeyboardInteractiveCallback != nil {
520
failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
523
if len(failureMsg.Methods) == 0 {
524
return errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
527
if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil {
532
packet = []byte{msgUserAuthSuccess}
533
if err = s.writePacket(packet); err != nil {
540
// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
541
// asking the client on the other side of a ServerConn.
542
type sshClientKeyboardInteractive struct {
546
func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
547
if len(questions) != len(echos) {
548
return nil, errors.New("ssh: echos and questions must have equal length")
552
for i := range questions {
553
prompts = appendString(prompts, questions[i])
554
prompts = appendBool(prompts, echos[i])
557
if err := c.writePacket(marshal(msgUserAuthInfoRequest, userAuthInfoRequestMsg{
558
Instruction: instruction,
559
NumPrompts: uint32(len(questions)),
565
packet, err := c.readPacket()
569
if packet[0] != msgUserAuthInfoResponse {
570
return nil, UnexpectedMessageError{msgUserAuthInfoResponse, packet[0]}
574
n, packet, ok := parseUint32(packet)
575
if !ok || int(n) != len(questions) {
576
return nil, &ParseError{msgUserAuthInfoResponse}
579
for i := uint32(0); i < n; i++ {
580
ans, rest, ok := parseString(packet)
582
return nil, &ParseError{msgUserAuthInfoResponse}
585
answers = append(answers, string(ans))
588
if len(packet) != 0 {
589
return nil, errors.New("ssh: junk at end of message")
595
const defaultWindowSize = 32768
597
// Accept reads and processes messages on a ServerConn. It must be called
598
// in order to demultiplex messages to any resulting Channels.
599
func (s *ServerConn) Accept() (Channel, error) {
600
// TODO(dfc) s.lock is not held here so visibility of s.err is not guaranteed.
606
packet, err := s.readPacket()
613
// TODO(dfc) s.lock protects s.channels but isn't being held here.
614
for _, c := range s.channels {
625
// malformed data packet
626
return nil, ParseError{msgChannelData}
628
remoteId := binary.BigEndian.Uint32(packet[1:5])
630
c, ok := s.channels[remoteId]
635
if length := binary.BigEndian.Uint32(packet[5:9]); length > 0 {
637
c.handleData(packet[:length])
641
decoded, err := decode(packet)
645
switch msg := decoded.(type) {
646
case *channelOpenMsg:
647
if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
648
return nil, errors.New("ssh: invalid MaxPacketSize from peer")
653
remoteId: msg.PeersId,
654
remoteWin: window{Cond: newCond()},
655
maxPacket: msg.MaxPacketSize,
657
chanType: msg.ChanType,
658
extraData: msg.TypeSpecificData,
659
myWindow: defaultWindowSize,
662
pendingData: make([]byte, defaultWindowSize),
664
c.remoteWin.add(msg.PeersWindow)
666
c.localId = s.nextChanId
668
s.channels[c.localId] = c
672
case *channelRequestMsg:
674
c, ok := s.channels[msg.PeersId]
682
case *windowAdjustMsg:
684
c, ok := s.channels[msg.PeersId]
694
c, ok := s.channels[msg.PeersId]
702
case *channelCloseMsg:
704
c, ok := s.channels[msg.PeersId]
712
case *globalRequestMsg:
714
if err := s.writePacket([]byte{msgRequestFailure}); err != nil {
721
if err := s.clientInitHandshake(msg, packet); err != nil {
729
// Unknown message. Ignore.
737
// A Listener implements a network listener (net.Listener) for SSH connections.
738
type Listener struct {
739
listener net.Listener
743
// Addr returns the listener's network address.
744
func (l *Listener) Addr() net.Addr {
745
return l.listener.Addr()
748
// Close closes the listener.
749
func (l *Listener) Close() error {
750
return l.listener.Close()
753
// Accept waits for and returns the next incoming SSH connection.
754
// The receiver should call Handshake() in another goroutine
755
// to avoid blocking the accepter.
756
func (l *Listener) Accept() (*ServerConn, error) {
757
c, err := l.listener.Accept()
761
return Server(c, l.config), nil
764
// Listen creates an SSH listener accepting connections on
765
// the given network address using net.Listen.
766
func Listen(network, addr string, config *ServerConfig) (*Listener, error) {
767
l, err := net.Listen(network, addr)