435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
140 lines
5.4 KiB
Go
140 lines
5.4 KiB
Go
// 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
|
|
}
|