summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh')
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher.go24
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth.go114
-rw-r--r--vendor/golang.org/x/crypto/ssh/common.go20
-rw-r--r--vendor/golang.org/x/crypto/ssh/handshake.go5
-rw-r--r--vendor/golang.org/x/crypto/ssh/messages.go70
-rw-r--r--vendor/golang.org/x/crypto/ssh/server.go118
-rw-r--r--vendor/golang.org/x/crypto/ssh/ssh_gss.go139
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/terminal.go67
-rw-r--r--vendor/golang.org/x/crypto/ssh/transport.go12
9 files changed, 513 insertions, 56 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go
index 67b01261..a65a923b 100644
--- a/vendor/golang.org/x/crypto/ssh/cipher.go
+++ b/vendor/golang.org/x/crypto/ssh/cipher.go
@@ -149,8 +149,8 @@ type streamPacketCipher struct {
macResult []byte
}
-// readPacket reads and decrypt a single packet from the reader argument.
-func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+// readCipherPacket reads and decrypt a single packet from the reader argument.
+func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
return nil, err
}
@@ -221,8 +221,8 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
return s.packetData[:length-paddingLength-1], nil
}
-// writePacket encrypts and sends a packet of data to the writer argument
-func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+// writeCipherPacket encrypts and sends a packet of data to the writer argument
+func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
if len(packet) > maxPacket {
return errors.New("ssh: packet too large")
}
@@ -327,7 +327,7 @@ func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms)
const gcmTagSize = 16
-func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
// Pad out to multiple of 16 bytes. This is different from the
// stream cipher because that encrypts the length too.
padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple)
@@ -370,7 +370,7 @@ func (c *gcmCipher) incIV() {
}
}
-func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
return nil, err
}
@@ -486,8 +486,8 @@ type cbcError string
func (e cbcError) Error() string { return string(e) }
-func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
- p, err := c.readPacketLeaky(seqNum, r)
+func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+ p, err := c.readCipherPacketLeaky(seqNum, r)
if err != nil {
if _, ok := err.(cbcError); ok {
// Verification error: read a fixed amount of
@@ -500,7 +500,7 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
return p, err
}
-func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
+func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
blockSize := c.decrypter.BlockSize()
// Read the header, which will include some of the subsequent data in the
@@ -576,7 +576,7 @@ func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error)
return c.packetData[prefixLen:paddingStart], nil
}
-func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
// Length of encrypted portion of the packet (header, payload, padding).
@@ -665,7 +665,7 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA
return c, nil
}
-func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
s := chacha20.New(c.contentKey, nonce)
var polyKey [32]byte
@@ -723,7 +723,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
return plain, nil
}
-func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
+func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
s := chacha20.New(c.contentKey, nonce)
var polyKey [32]byte
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go
index 5f44b774..0590070e 100644
--- a/vendor/golang.org/x/crypto/ssh/client_auth.go
+++ b/vendor/golang.org/x/crypto/ssh/client_auth.go
@@ -523,3 +523,117 @@ func (r *retryableAuthMethod) method() string {
func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod {
return &retryableAuthMethod{authMethod: auth, maxTries: maxTries}
}
+
+// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication.
+// See RFC 4462 section 3
+// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details.
+// target is the server host you want to log in to.
+func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod {
+ if gssAPIClient == nil {
+ panic("gss-api client must be not nil with enable gssapi-with-mic")
+ }
+ return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target}
+}
+
+type gssAPIWithMICCallback struct {
+ gssAPIClient GSSAPIClient
+ target string
+}
+
+func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
+ m := &userAuthRequestMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: g.method(),
+ }
+ // The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST.
+ // See RFC 4462 section 3.2.
+ m.Payload = appendU32(m.Payload, 1)
+ m.Payload = appendString(m.Payload, string(krb5OID))
+ if err := c.writePacket(Marshal(m)); err != nil {
+ return authFailure, nil, err
+ }
+ // The server responds to the SSH_MSG_USERAUTH_REQUEST with either an
+ // SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or
+ // with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE.
+ // See RFC 4462 section 3.3.
+ // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check
+ // selected mech if it is valid.
+ packet, err := c.readPacket()
+ if err != nil {
+ return authFailure, nil, err
+ }
+ userAuthGSSAPIResp := &userAuthGSSAPIResponse{}
+ if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil {
+ return authFailure, nil, err
+ }
+ // Start the loop into the exchange token.
+ // See RFC 4462 section 3.4.
+ var token []byte
+ defer g.gssAPIClient.DeleteSecContext()
+ for {
+ // Initiates the establishment of a security context between the application and a remote peer.
+ nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false)
+ if err != nil {
+ return authFailure, nil, err
+ }
+ if len(nextToken) > 0 {
+ if err := c.writePacket(Marshal(&userAuthGSSAPIToken{
+ Token: nextToken,
+ })); err != nil {
+ return authFailure, nil, err
+ }
+ }
+ if !needContinue {
+ break
+ }
+ packet, err = c.readPacket()
+ if err != nil {
+ return authFailure, nil, err
+ }
+ switch packet[0] {
+ case msgUserAuthFailure:
+ var msg userAuthFailureMsg
+ if err := Unmarshal(packet, &msg); err != nil {
+ return authFailure, nil, err
+ }
+ if msg.PartialSuccess {
+ return authPartialSuccess, msg.Methods, nil
+ }
+ return authFailure, msg.Methods, nil
+ case msgUserAuthGSSAPIError:
+ userAuthGSSAPIErrorResp := &userAuthGSSAPIError{}
+ if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil {
+ return authFailure, nil, err
+ }
+ return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+
+ "Major Status: %d\n"+
+ "Minor Status: %d\n"+
+ "Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus,
+ userAuthGSSAPIErrorResp.Message)
+ case msgUserAuthGSSAPIToken:
+ userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
+ if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
+ return authFailure, nil, err
+ }
+ token = userAuthGSSAPITokenReq.Token
+ }
+ }
+ // Binding Encryption Keys.
+ // See RFC 4462 section 3.5.
+ micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic")
+ micToken, err := g.gssAPIClient.GetMIC(micField)
+ if err != nil {
+ return authFailure, nil, err
+ }
+ if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{
+ MIC: micToken,
+ })); err != nil {
+ return authFailure, nil, err
+ }
+ return handleAuthResponse(c)
+}
+
+func (g *gssAPIWithMICCallback) method() string {
+ return "gssapi-with-mic"
+}
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
index 04f3620b..d97415d2 100644
--- a/vendor/golang.org/x/crypto/ssh/common.go
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -109,6 +109,7 @@ func findCommon(what string, client []string, server []string) (common string, e
return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server)
}
+// directionAlgorithms records algorithm choices in one direction (either read or write)
type directionAlgorithms struct {
Cipher string
MAC string
@@ -137,7 +138,7 @@ type algorithms struct {
r directionAlgorithms
}
-func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
+func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
result := &algorithms{}
result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos)
@@ -150,32 +151,37 @@ func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor
return
}
- result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
+ stoc, ctos := &result.w, &result.r
+ if isClient {
+ ctos, stoc = stoc, ctos
+ }
+
+ ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
if err != nil {
return
}
- result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
+ stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
if err != nil {
return
}
- result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
+ ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
if err != nil {
return
}
- result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
+ stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
if err != nil {
return
}
- result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
+ ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
if err != nil {
return
}
- result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
+ stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
if err != nil {
return
}
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
index 4f7912ec..2b10b05a 100644
--- a/vendor/golang.org/x/crypto/ssh/handshake.go
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -543,7 +543,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
clientInit := otherInit
serverInit := t.sentInitMsg
- if len(t.hostKeys) == 0 {
+ isClient := len(t.hostKeys) == 0
+ if isClient {
clientInit, serverInit = serverInit, clientInit
magics.clientKexInit = t.sentInitPacket
@@ -551,7 +552,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
}
var err error
- t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit)
+ t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit)
if err != nil {
return err
}
diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go
index 08d28117..db914d80 100644
--- a/vendor/golang.org/x/crypto/ssh/messages.go
+++ b/vendor/golang.org/x/crypto/ssh/messages.go
@@ -275,6 +275,42 @@ type userAuthPubKeyOkMsg struct {
PubKey []byte
}
+// 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
+}
+
// 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) {
@@ -756,6 +792,14 @@ func decode(packet []byte) (interface{}, error) {
msg = new(channelRequestSuccessMsg)
case msgChannelFailure:
msg = new(channelRequestFailureMsg)
+ case msgUserAuthGSSAPIToken:
+ msg = new(userAuthGSSAPIToken)
+ case msgUserAuthGSSAPIMIC:
+ msg = new(userAuthGSSAPIMIC)
+ case msgUserAuthGSSAPIErrTok:
+ msg = new(userAuthGSSAPIErrTok)
+ case msgUserAuthGSSAPIError:
+ msg = new(userAuthGSSAPIError)
default:
return nil, unexpectedMessageError(0, packet[0])
}
@@ -764,3 +808,29 @@ func decode(packet []byte) (interface{}, error) {
}
return msg, nil
}
+
+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",
+}
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
index e86e8966..ac7f8073 100644
--- a/vendor/golang.org/x/crypto/ssh/server.go
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -45,6 +45,20 @@ type Permissions struct {
Extensions map[string]string
}
+type GSSAPIWithMICConfig struct {
+ // AllowLogin, must be set, is called when gssapi-with-mic
+ // authentication is selected (RFC 4462 section 3). The srcName is from the
+ // results of the GSS-API authentication. The format is username@DOMAIN.
+ // GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
+ // This callback is called after the user identity is established with GSSAPI to decide if the user can login with
+ // which permissions. If the user is allowed to login, it should return a nil error.
+ AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
+
+ // Server must be set. It's the implementation
+ // of the GSSAPIServer interface. See GSSAPIServer interface for details.
+ Server GSSAPIServer
+}
+
// ServerConfig holds server specific configuration data.
type ServerConfig struct {
// Config contains configuration shared between client and server.
@@ -99,6 +113,10 @@ type ServerConfig struct {
// BannerCallback, if present, is called and the return string is sent to
// the client after key exchange completed but before authentication.
BannerCallback func(conn ConnMetadata) string
+
+ // GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
+ // when gssapi-with-mic authentication is selected (RFC 4462 section 3).
+ GSSAPIWithMICConfig *GSSAPIWithMICConfig
}
// AddHostKey adds a private key as a host key. If an existing host
@@ -204,7 +222,9 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error)
return nil, errors.New("ssh: server has no host keys")
}
- if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil {
+ if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
+ config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
+ config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
}
@@ -295,6 +315,55 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
}
+func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
+ sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
+ gssAPIServer := gssapiConfig.Server
+ defer gssAPIServer.DeleteSecContext()
+ var srcName string
+ for {
+ var (
+ outToken []byte
+ needContinue bool
+ )
+ outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
+ if err != nil {
+ return err, nil, nil
+ }
+ if len(outToken) != 0 {
+ if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
+ Token: outToken,
+ })); err != nil {
+ return nil, nil, err
+ }
+ }
+ if !needContinue {
+ break
+ }
+ packet, err := s.transport.readPacket()
+ if err != nil {
+ return nil, nil, err
+ }
+ userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
+ if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
+ return nil, nil, err
+ }
+ }
+ packet, err := s.transport.readPacket()
+ if err != nil {
+ return nil, nil, err
+ }
+ userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
+ if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
+ return nil, nil, err
+ }
+ mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
+ if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
+ return err, nil, nil
+ }
+ perms, authErr = gssapiConfig.AllowLogin(s, srcName)
+ return authErr, perms, nil
+}
+
// ServerAuthError represents server authentication errors and is
// sometimes returned by NewServerConn. It appends any authentication
// errors that may occur, and is returned if all of the authentication
@@ -496,6 +565,49 @@ userAuthLoop:
authErr = candidate.result
perms = candidate.perms
}
+ case "gssapi-with-mic":
+ gssapiConfig := config.GSSAPIWithMICConfig
+ userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
+ if err != nil {
+ return nil, parseError(msgUserAuthRequest)
+ }
+ // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
+ if userAuthRequestGSSAPI.N == 0 {
+ authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
+ break
+ }
+ var i uint32
+ present := false
+ for i = 0; i < userAuthRequestGSSAPI.N; i++ {
+ if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
+ present = true
+ break
+ }
+ }
+ if !present {
+ authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
+ break
+ }
+ // Initial server response, see RFC 4462 section 3.3.
+ if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
+ SupportMech: krb5OID,
+ })); err != nil {
+ return nil, err
+ }
+ // Exchange token, see RFC 4462 section 3.4.
+ packet, err := s.transport.readPacket()
+ if err != nil {
+ return nil, err
+ }
+ userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
+ if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
+ return nil, err
+ }
+ authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
+ userAuthReq)
+ if err != nil {
+ return nil, err
+ }
default:
authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
}
@@ -522,6 +634,10 @@ userAuthLoop:
if config.KeyboardInteractiveCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
}
+ if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil &&
+ config.GSSAPIWithMICConfig.AllowLogin != nil {
+ failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
+ }
if len(failureMsg.Methods) == 0 {
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
diff --git a/vendor/golang.org/x/crypto/ssh/ssh_gss.go b/vendor/golang.org/x/crypto/ssh/ssh_gss.go
new file mode 100644
index 00000000..24bd7c8e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/ssh_gss.go
@@ -0,0 +1,139 @@
+// 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 (
+ "encoding/asn1"
+ "errors"
+)
+
+var krb5OID []byte
+
+func init() {
+ krb5OID, _ = asn1.Marshal(krb5Mesh)
+}
+
+// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins.
+type GSSAPIClient interface {
+ // InitSecContext initiates the establishment of a security context for GSS-API between the
+ // ssh client and ssh server. Initially the token parameter should be specified as nil.
+ // The routine may return a outputToken which should be transferred to
+ // the ssh server, where the ssh server will present it to
+ // AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting
+ // needContinue to false. To complete the context
+ // establishment, one or more reply tokens may be required from the ssh
+ // server;if so, InitSecContext will return a needContinue which is true.
+ // In this case, InitSecContext should be called again when the
+ // reply token is received from the ssh server, passing the reply
+ // token to InitSecContext via the token parameters.
+ // See RFC 2743 section 2.2.1 and RFC 4462 section 3.4.
+ InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error)
+ // GetMIC generates a cryptographic MIC for the SSH2 message, and places
+ // the MIC in a token for transfer to the ssh server.
+ // The contents of the MIC field are obtained by calling GSS_GetMIC()
+ // over the following, using the GSS-API context that was just
+ // established:
+ // string session identifier
+ // byte SSH_MSG_USERAUTH_REQUEST
+ // string user name
+ // string service
+ // string "gssapi-with-mic"
+ // See RFC 2743 section 2.3.1 and RFC 4462 3.5.
+ GetMIC(micFiled []byte) ([]byte, error)
+ // Whenever possible, it should be possible for
+ // DeleteSecContext() calls to be successfully processed even
+ // if other calls cannot succeed, thereby enabling context-related
+ // resources to be released.
+ // In addition to deleting established security contexts,
+ // gss_delete_sec_context must also be able to delete "half-built"
+ // security contexts resulting from an incomplete sequence of
+ // InitSecContext()/AcceptSecContext() calls.
+ // See RFC 2743 section 2.2.3.
+ DeleteSecContext() error
+}
+
+// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins.
+type GSSAPIServer interface {
+ // AcceptSecContext allows a remotely initiated security context between the application
+ // and a remote peer to be established by the ssh client. The routine may return a
+ // outputToken which should be transferred to the ssh client,
+ // where the ssh client will present it to InitSecContext.
+ // If no token need be sent, AcceptSecContext will indicate this
+ // by setting the needContinue to false. To
+ // complete the context establishment, one or more reply tokens may be
+ // required from the ssh client. if so, AcceptSecContext
+ // will return a needContinue which is true, in which case it
+ // should be called again when the reply token is received from the ssh
+ // client, passing the token to AcceptSecContext via the
+ // token parameters.
+ // The srcName return value is the authenticated username.
+ // See RFC 2743 section 2.2.2 and RFC 4462 section 3.4.
+ AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error)
+ // VerifyMIC verifies that a cryptographic MIC, contained in the token parameter,
+ // fits the supplied message is received from the ssh client.
+ // See RFC 2743 section 2.3.2.
+ VerifyMIC(micField []byte, micToken []byte) error
+ // Whenever possible, it should be possible for
+ // DeleteSecContext() calls to be successfully processed even
+ // if other calls cannot succeed, thereby enabling context-related
+ // resources to be released.
+ // In addition to deleting established security contexts,
+ // gss_delete_sec_context must also be able to delete "half-built"
+ // security contexts resulting from an incomplete sequence of
+ // InitSecContext()/AcceptSecContext() calls.
+ // See RFC 2743 section 2.2.3.
+ DeleteSecContext() error
+}
+
+var (
+ // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,
+ // so we also support the krb5 mechanism only.
+ // See RFC 1964 section 1.
+ krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
+)
+
+// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST
+// See RFC 4462 section 3.2.
+type userAuthRequestGSSAPI struct {
+ N uint32
+ OIDS []asn1.ObjectIdentifier
+}
+
+func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
+ n, rest, ok := parseUint32(payload)
+ if !ok {
+ return nil, errors.New("parse uint32 failed")
+ }
+ s := &userAuthRequestGSSAPI{
+ N: n,
+ OIDS: make([]asn1.ObjectIdentifier, n),
+ }
+ for i := 0; i < int(n); i++ {
+ var (
+ desiredMech []byte
+ err error
+ )
+ desiredMech, rest, ok = parseString(rest)
+ if !ok {
+ return nil, errors.New("parse string failed")
+ }
+ if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
+ return nil, err
+ }
+
+ }
+ return s, nil
+}
+
+// See RFC 4462 section 3.6.
+func buildMIC(sessionID string, username string, service string, authMethod string) []byte {
+ out := make([]byte, 0, 0)
+ out = appendString(out, sessionID)
+ out = append(out, msgUserAuthRequest)
+ out = appendString(out, username)
+ out = appendString(out, service)
+ out = appendString(out, authMethod)
+ return out
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
index 9d666ffc..2f04ee5b 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
@@ -7,6 +7,7 @@ package terminal
import (
"bytes"
"io"
+ "strconv"
"sync"
"unicode/utf8"
)
@@ -271,34 +272,44 @@ func (t *Terminal) moveCursorToPos(pos int) {
}
func (t *Terminal) move(up, down, left, right int) {
- movement := make([]rune, 3*(up+down+left+right))
- m := movement
- for i := 0; i < up; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'A'
- m = m[3:]
- }
- for i := 0; i < down; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'B'
- m = m[3:]
- }
- for i := 0; i < left; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'D'
- m = m[3:]
- }
- for i := 0; i < right; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'C'
- m = m[3:]
- }
-
- t.queue(movement)
+ m := []rune{}
+
+ // 1 unit up can be expressed as ^[[A or ^[A
+ // 5 units up can be expressed as ^[[5A
+
+ if up == 1 {
+ m = append(m, keyEscape, '[', 'A')
+ } else if up > 1 {
+ m = append(m, keyEscape, '[')
+ m = append(m, []rune(strconv.Itoa(up))...)
+ m = append(m, 'A')
+ }
+
+ if down == 1 {
+ m = append(m, keyEscape, '[', 'B')
+ } else if down > 1 {
+ m = append(m, keyEscape, '[')
+ m = append(m, []rune(strconv.Itoa(down))...)
+ m = append(m, 'B')
+ }
+
+ if right == 1 {
+ m = append(m, keyEscape, '[', 'C')
+ } else if right > 1 {
+ m = append(m, keyEscape, '[')
+ m = append(m, []rune(strconv.Itoa(right))...)
+ m = append(m, 'C')
+ }
+
+ if left == 1 {
+ m = append(m, keyEscape, '[', 'D')
+ } else if left > 1 {
+ m = append(m, keyEscape, '[')
+ m = append(m, []rune(strconv.Itoa(left))...)
+ m = append(m, 'D')
+ }
+
+ t.queue(m)
}
func (t *Terminal) clearLineToRight() {
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go
index f6fae1db..49ddc2e7 100644
--- a/vendor/golang.org/x/crypto/ssh/transport.go
+++ b/vendor/golang.org/x/crypto/ssh/transport.go
@@ -53,14 +53,14 @@ type transport struct {
// packetCipher represents a combination of SSH encryption/MAC
// protocol. A single instance should be used for one direction only.
type packetCipher interface {
- // writePacket encrypts the packet and writes it to w. The
+ // writeCipherPacket encrypts the packet and writes it to w. The
// contents of the packet are generally scrambled.
- writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
+ writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
- // readPacket reads and decrypts a packet of data. The
+ // readCipherPacket reads and decrypts a packet of data. The
// returned packet may be overwritten by future calls of
// readPacket.
- readPacket(seqnum uint32, r io.Reader) ([]byte, error)
+ readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error)
}
// connectionState represents one side (read or write) of the
@@ -127,7 +127,7 @@ func (t *transport) readPacket() (p []byte, err error) {
}
func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
- packet, err := s.packetCipher.readPacket(s.seqNum, r)
+ packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
s.seqNum++
if err == nil && len(packet) == 0 {
err = errors.New("ssh: zero length packet")
@@ -175,7 +175,7 @@ func (t *transport) writePacket(packet []byte) error {
func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
- err := s.packetCipher.writePacket(s.seqNum, w, rand, packet)
+ err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
if err != nil {
return err
}