mirror of
https://gitea.com/gitea/tea.git
synced 2024-11-30 06:16:53 +01:00
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
|
||
|
}
|