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	"errors"
10	"fmt"
11	"io"
12	"net"
13	"strings"
14)
15
16// The Permissions type holds fine-grained permissions that are
17// specific to a user or a specific authentication method for a user.
18// The Permissions value for a successful authentication attempt is
19// available in ServerConn, so it can be used to pass information from
20// the user-authentication phase to the application layer.
21type Permissions struct {
22	// CriticalOptions indicate restrictions to the default
23	// permissions, and are typically used in conjunction with
24	// user certificates. The standard for SSH certificates
25	// defines "force-command" (only allow the given command to
26	// execute) and "source-address" (only allow connections from
27	// the given address). The SSH package currently only enforces
28	// the "source-address" critical option. It is up to server
29	// implementations to enforce other critical options, such as
30	// "force-command", by checking them after the SSH handshake
31	// is successful. In general, SSH servers should reject
32	// connections that specify critical options that are unknown
33	// or not supported.
34	CriticalOptions map[string]string
35
36	// Extensions are extra functionality that the server may
37	// offer on authenticated connections. Lack of support for an
38	// extension does not preclude authenticating a user. Common
39	// extensions are "permit-agent-forwarding",
40	// "permit-X11-forwarding". The Go SSH library currently does
41	// not act on any extension, and it is up to server
42	// implementations to honor them. Extensions can be used to
43	// pass data from the authentication callbacks to the server
44	// application layer.
45	Extensions map[string]string
46}
47
48type GSSAPIWithMICConfig struct {
49	// AllowLogin, must be set, is called when gssapi-with-mic
50	// authentication is selected (RFC 4462 section 3). The srcName is from the
51	// results of the GSS-API authentication. The format is username@DOMAIN.
52	// GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
53	// This callback is called after the user identity is established with GSSAPI to decide if the user can login with
54	// which permissions. If the user is allowed to login, it should return a nil error.
55	AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
56
57	// Server must be set. It's the implementation
58	// of the GSSAPIServer interface. See GSSAPIServer interface for details.
59	Server GSSAPIServer
60}
61
62// ServerConfig holds server specific configuration data.
63type ServerConfig struct {
64	// Config contains configuration shared between client and server.
65	Config
66
67	hostKeys []Signer
68
69	// NoClientAuth is true if clients are allowed to connect without
70	// authenticating.
71	NoClientAuth bool
72
73	// MaxAuthTries specifies the maximum number of authentication attempts
74	// permitted per connection. If set to a negative number, the number of
75	// attempts are unlimited. If set to zero, the number of attempts are limited
76	// to 6.
77	MaxAuthTries int
78
79	// PasswordCallback, if non-nil, is called when a user
80	// attempts to authenticate using a password.
81	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
82
83	// PublicKeyCallback, if non-nil, is called when a client
84	// offers a public key for authentication. It must return a nil error
85	// if the given public key can be used to authenticate the
86	// given user. For example, see CertChecker.Authenticate. A
87	// call to this function does not guarantee that the key
88	// offered is in fact used to authenticate. To record any data
89	// depending on the public key, store it inside a
90	// Permissions.Extensions entry.
91	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
92
93	// KeyboardInteractiveCallback, if non-nil, is called when
94	// keyboard-interactive authentication is selected (RFC
95	// 4256). The client object's Challenge function should be
96	// used to query the user. The callback may offer multiple
97	// Challenge rounds. To avoid information leaks, the client
98	// should be presented a challenge even if the user is
99	// unknown.
100	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
101
102	// AuthLogCallback, if non-nil, is called to log all authentication
103	// attempts.
104	AuthLogCallback func(conn ConnMetadata, method string, err error)
105
106	// ServerVersion is the version identification string to announce in
107	// the public handshake.
108	// If empty, a reasonable default is used.
109	// Note that RFC 4253 section 4.2 requires that this string start with
110	// "SSH-2.0-".
111	ServerVersion string
112
113	// BannerCallback, if present, is called and the return string is sent to
114	// the client after key exchange completed but before authentication.
115	BannerCallback func(conn ConnMetadata) string
116
117	// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
118	// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
119	GSSAPIWithMICConfig *GSSAPIWithMICConfig
120}
121
122// AddHostKey adds a private key as a host key. If an existing host
123// key exists with the same algorithm, it is overwritten. Each server
124// config must have at least one host key.
125func (s *ServerConfig) AddHostKey(key Signer) {
126	for i, k := range s.hostKeys {
127		if k.PublicKey().Type() == key.PublicKey().Type() {
128			s.hostKeys[i] = key
129			return
130		}
131	}
132
133	s.hostKeys = append(s.hostKeys, key)
134}
135
136// cachedPubKey contains the results of querying whether a public key is
137// acceptable for a user.
138type cachedPubKey struct {
139	user       string
140	pubKeyData []byte
141	result     error
142	perms      *Permissions
143}
144
145const maxCachedPubKeys = 16
146
147// pubKeyCache caches tests for public keys.  Since SSH clients
148// will query whether a public key is acceptable before attempting to
149// authenticate with it, we end up with duplicate queries for public
150// key validity.  The cache only applies to a single ServerConn.
151type pubKeyCache struct {
152	keys []cachedPubKey
153}
154
155// get returns the result for a given user/algo/key tuple.
156func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
157	for _, k := range c.keys {
158		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
159			return k, true
160		}
161	}
162	return cachedPubKey{}, false
163}
164
165// add adds the given tuple to the cache.
166func (c *pubKeyCache) add(candidate cachedPubKey) {
167	if len(c.keys) < maxCachedPubKeys {
168		c.keys = append(c.keys, candidate)
169	}
170}
171
172// ServerConn is an authenticated SSH connection, as seen from the
173// server
174type ServerConn struct {
175	Conn
176
177	// If the succeeding authentication callback returned a
178	// non-nil Permissions pointer, it is stored here.
179	Permissions *Permissions
180}
181
182// NewServerConn starts a new SSH server with c as the underlying
183// transport.  It starts with a handshake and, if the handshake is
184// unsuccessful, it closes the connection and returns an error.  The
185// Request and NewChannel channels must be serviced, or the connection
186// will hang.
187//
188// The returned error may be of type *ServerAuthError for
189// authentication errors.
190func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
191	fullConf := *config
192	fullConf.SetDefaults()
193	if fullConf.MaxAuthTries == 0 {
194		fullConf.MaxAuthTries = 6
195	}
196	// Check if the config contains any unsupported key exchanges
197	for _, kex := range fullConf.KeyExchanges {
198		if _, ok := serverForbiddenKexAlgos[kex]; ok {
199			return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
200		}
201	}
202
203	s := &connection{
204		sshConn: sshConn{conn: c},
205	}
206	perms, err := s.serverHandshake(&fullConf)
207	if err != nil {
208		c.Close()
209		return nil, nil, nil, err
210	}
211	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
212}
213
214// signAndMarshal signs the data with the appropriate algorithm,
215// and serializes the result in SSH wire format.
216func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
217	sig, err := k.Sign(rand, data)
218	if err != nil {
219		return nil, err
220	}
221
222	return Marshal(sig), nil
223}
224
225// handshake performs key exchange and user authentication.
226func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
227	if len(config.hostKeys) == 0 {
228		return nil, errors.New("ssh: server has no host keys")
229	}
230
231	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
232		config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
233		config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
234		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
235	}
236
237	if config.ServerVersion != "" {
238		s.serverVersion = []byte(config.ServerVersion)
239	} else {
240		s.serverVersion = []byte(packageVersion)
241	}
242	var err error
243	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
244	if err != nil {
245		return nil, err
246	}
247
248	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
249	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
250
251	if err := s.transport.waitSession(); err != nil {
252		return nil, err
253	}
254
255	// We just did the key change, so the session ID is established.
256	s.sessionID = s.transport.getSessionID()
257
258	var packet []byte
259	if packet, err = s.transport.readPacket(); err != nil {
260		return nil, err
261	}
262
263	var serviceRequest serviceRequestMsg
264	if err = Unmarshal(packet, &serviceRequest); err != nil {
265		return nil, err
266	}
267	if serviceRequest.Service != serviceUserAuth {
268		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
269	}
270	serviceAccept := serviceAcceptMsg{
271		Service: serviceUserAuth,
272	}
273	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
274		return nil, err
275	}
276
277	perms, err := s.serverAuthenticate(config)
278	if err != nil {
279		return nil, err
280	}
281	s.mux = newMux(s.transport)
282	return perms, err
283}
284
285func isAcceptableAlgo(algo string) bool {
286	switch algo {
287	case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519,
288		CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
289		return true
290	}
291	return false
292}
293
294func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
295	if addr == nil {
296		return errors.New("ssh: no address known for client, but source-address match required")
297	}
298
299	tcpAddr, ok := addr.(*net.TCPAddr)
300	if !ok {
301		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
302	}
303
304	for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
305		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
306			if allowedIP.Equal(tcpAddr.IP) {
307				return nil
308			}
309		} else {
310			_, ipNet, err := net.ParseCIDR(sourceAddr)
311			if err != nil {
312				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
313			}
314
315			if ipNet.Contains(tcpAddr.IP) {
316				return nil
317			}
318		}
319	}
320
321	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
322}
323
324func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
325	sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
326	gssAPIServer := gssapiConfig.Server
327	defer gssAPIServer.DeleteSecContext()
328	var srcName string
329	for {
330		var (
331			outToken     []byte
332			needContinue bool
333		)
334		outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
335		if err != nil {
336			return err, nil, nil
337		}
338		if len(outToken) != 0 {
339			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
340				Token: outToken,
341			})); err != nil {
342				return nil, nil, err
343			}
344		}
345		if !needContinue {
346			break
347		}
348		packet, err := s.transport.readPacket()
349		if err != nil {
350			return nil, nil, err
351		}
352		userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
353		if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
354			return nil, nil, err
355		}
356	}
357	packet, err := s.transport.readPacket()
358	if err != nil {
359		return nil, nil, err
360	}
361	userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
362	if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
363		return nil, nil, err
364	}
365	mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
366	if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
367		return err, nil, nil
368	}
369	perms, authErr = gssapiConfig.AllowLogin(s, srcName)
370	return authErr, perms, nil
371}
372
373// ServerAuthError represents server authentication errors and is
374// sometimes returned by NewServerConn. It appends any authentication
375// errors that may occur, and is returned if all of the authentication
376// methods provided by the user failed to authenticate.
377type ServerAuthError struct {
378	// Errors contains authentication errors returned by the authentication
379	// callback methods. The first entry is typically ErrNoAuth.
380	Errors []error
381}
382
383func (l ServerAuthError) Error() string {
384	var errs []string
385	for _, err := range l.Errors {
386		errs = append(errs, err.Error())
387	}
388	return "[" + strings.Join(errs, ", ") + "]"
389}
390
391// ErrNoAuth is the error value returned if no
392// authentication method has been passed yet. This happens as a normal
393// part of the authentication loop, since the client first tries
394// 'none' authentication to discover available methods.
395// It is returned in ServerAuthError.Errors from NewServerConn.
396var ErrNoAuth = errors.New("ssh: no auth passed yet")
397
398func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
399	sessionID := s.transport.getSessionID()
400	var cache pubKeyCache
401	var perms *Permissions
402
403	authFailures := 0
404	var authErrs []error
405	var displayedBanner bool
406
407userAuthLoop:
408	for {
409		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
410			discMsg := &disconnectMsg{
411				Reason:  2,
412				Message: "too many authentication failures",
413			}
414
415			if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
416				return nil, err
417			}
418
419			return nil, discMsg
420		}
421
422		var userAuthReq userAuthRequestMsg
423		if packet, err := s.transport.readPacket(); err != nil {
424			if err == io.EOF {
425				return nil, &ServerAuthError{Errors: authErrs}
426			}
427			return nil, err
428		} else if err = Unmarshal(packet, &userAuthReq); err != nil {
429			return nil, err
430		}
431
432		if userAuthReq.Service != serviceSSH {
433			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
434		}
435
436		s.user = userAuthReq.User
437
438		if !displayedBanner && config.BannerCallback != nil {
439			displayedBanner = true
440			msg := config.BannerCallback(s)
441			if msg != "" {
442				bannerMsg := &userAuthBannerMsg{
443					Message: msg,
444				}
445				if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
446					return nil, err
447				}
448			}
449		}
450
451		perms = nil
452		authErr := ErrNoAuth
453
454		switch userAuthReq.Method {
455		case "none":
456			if config.NoClientAuth {
457				authErr = nil
458			}
459
460			// allow initial attempt of 'none' without penalty
461			if authFailures == 0 {
462				authFailures--
463			}
464		case "password":
465			if config.PasswordCallback == nil {
466				authErr = errors.New("ssh: password auth not configured")
467				break
468			}
469			payload := userAuthReq.Payload
470			if len(payload) < 1 || payload[0] != 0 {
471				return nil, parseError(msgUserAuthRequest)
472			}
473			payload = payload[1:]
474			password, payload, ok := parseString(payload)
475			if !ok || len(payload) > 0 {
476				return nil, parseError(msgUserAuthRequest)
477			}
478
479			perms, authErr = config.PasswordCallback(s, password)
480		case "keyboard-interactive":
481			if config.KeyboardInteractiveCallback == nil {
482				authErr = errors.New("ssh: keyboard-interactive auth not configured")
483				break
484			}
485
486			prompter := &sshClientKeyboardInteractive{s}
487			perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge)
488		case "publickey":
489			if config.PublicKeyCallback == nil {
490				authErr = errors.New("ssh: publickey auth not configured")
491				break
492			}
493			payload := userAuthReq.Payload
494			if len(payload) < 1 {
495				return nil, parseError(msgUserAuthRequest)
496			}
497			isQuery := payload[0] == 0
498			payload = payload[1:]
499			algoBytes, payload, ok := parseString(payload)
500			if !ok {
501				return nil, parseError(msgUserAuthRequest)
502			}
503			algo := string(algoBytes)
504			if !isAcceptableAlgo(algo) {
505				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
506				break
507			}
508
509			pubKeyData, payload, ok := parseString(payload)
510			if !ok {
511				return nil, parseError(msgUserAuthRequest)
512			}
513
514			pubKey, err := ParsePublicKey(pubKeyData)
515			if err != nil {
516				return nil, err
517			}
518
519			candidate, ok := cache.get(s.user, pubKeyData)
520			if !ok {
521				candidate.user = s.user
522				candidate.pubKeyData = pubKeyData
523				candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey)
524				if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
525					candidate.result = checkSourceAddress(
526						s.RemoteAddr(),
527						candidate.perms.CriticalOptions[sourceAddressCriticalOption])
528				}
529				cache.add(candidate)
530			}
531
532			if isQuery {
533				// The client can query if the given public key
534				// would be okay.
535
536				if len(payload) > 0 {
537					return nil, parseError(msgUserAuthRequest)
538				}
539
540				if candidate.result == nil {
541					okMsg := userAuthPubKeyOkMsg{
542						Algo:   algo,
543						PubKey: pubKeyData,
544					}
545					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
546						return nil, err
547					}
548					continue userAuthLoop
549				}
550				authErr = candidate.result
551			} else {
552				sig, payload, ok := parseSignature(payload)
553				if !ok || len(payload) > 0 {
554					return nil, parseError(msgUserAuthRequest)
555				}
556				// Ensure the public key algo and signature algo
557				// are supported.  Compare the private key
558				// algorithm name that corresponds to algo with
559				// sig.Format.  This is usually the same, but
560				// for certs, the names differ.
561				if !isAcceptableAlgo(sig.Format) {
562					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
563					break
564				}
565				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData)
566
567				if err := pubKey.Verify(signedData, sig); err != nil {
568					return nil, err
569				}
570
571				authErr = candidate.result
572				perms = candidate.perms
573			}
574		case "gssapi-with-mic":
575			if config.GSSAPIWithMICConfig == nil {
576				authErr = errors.New("ssh: gssapi-with-mic auth not configured")
577				break
578			}
579			gssapiConfig := config.GSSAPIWithMICConfig
580			userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
581			if err != nil {
582				return nil, parseError(msgUserAuthRequest)
583			}
584			// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
585			if userAuthRequestGSSAPI.N == 0 {
586				authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
587				break
588			}
589			var i uint32
590			present := false
591			for i = 0; i < userAuthRequestGSSAPI.N; i++ {
592				if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
593					present = true
594					break
595				}
596			}
597			if !present {
598				authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
599				break
600			}
601			// Initial server response, see RFC 4462 section 3.3.
602			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
603				SupportMech: krb5OID,
604			})); err != nil {
605				return nil, err
606			}
607			// Exchange token, see RFC 4462 section 3.4.
608			packet, err := s.transport.readPacket()
609			if err != nil {
610				return nil, err
611			}
612			userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
613			if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
614				return nil, err
615			}
616			authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
617				userAuthReq)
618			if err != nil {
619				return nil, err
620			}
621		default:
622			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
623		}
624
625		authErrs = append(authErrs, authErr)
626
627		if config.AuthLogCallback != nil {
628			config.AuthLogCallback(s, userAuthReq.Method, authErr)
629		}
630
631		if authErr == nil {
632			break userAuthLoop
633		}
634
635		authFailures++
636
637		var failureMsg userAuthFailureMsg
638		if config.PasswordCallback != nil {
639			failureMsg.Methods = append(failureMsg.Methods, "password")
640		}
641		if config.PublicKeyCallback != nil {
642			failureMsg.Methods = append(failureMsg.Methods, "publickey")
643		}
644		if config.KeyboardInteractiveCallback != nil {
645			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
646		}
647		if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil &&
648			config.GSSAPIWithMICConfig.AllowLogin != nil {
649			failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
650		}
651
652		if len(failureMsg.Methods) == 0 {
653			return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
654		}
655
656		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
657			return nil, err
658		}
659	}
660
661	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
662		return nil, err
663	}
664	return perms, nil
665}
666
667// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
668// asking the client on the other side of a ServerConn.
669type sshClientKeyboardInteractive struct {
670	*connection
671}
672
673func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
674	if len(questions) != len(echos) {
675		return nil, errors.New("ssh: echos and questions must have equal length")
676	}
677
678	var prompts []byte
679	for i := range questions {
680		prompts = appendString(prompts, questions[i])
681		prompts = appendBool(prompts, echos[i])
682	}
683
684	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
685		Instruction: instruction,
686		NumPrompts:  uint32(len(questions)),
687		Prompts:     prompts,
688	})); err != nil {
689		return nil, err
690	}
691
692	packet, err := c.transport.readPacket()
693	if err != nil {
694		return nil, err
695	}
696	if packet[0] != msgUserAuthInfoResponse {
697		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
698	}
699	packet = packet[1:]
700
701	n, packet, ok := parseUint32(packet)
702	if !ok || int(n) != len(questions) {
703		return nil, parseError(msgUserAuthInfoResponse)
704	}
705
706	for i := uint32(0); i < n; i++ {
707		ans, rest, ok := parseString(packet)
708		if !ok {
709			return nil, parseError(msgUserAuthInfoResponse)
710		}
711
712		answers = append(answers, string(ans))
713		packet = rest
714	}
715	if len(packet) != 0 {
716		return nil, errors.New("ssh: junk at end of message")
717	}
718
719	return answers, nil
720}
721