github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/crypto/ssh/ssh_gss.go (about)

     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  
     5  package ssh
     6  
     7  import (
     8  	"encoding/asn1"
     9  	"errors"
    10  )
    11  
    12  var krb5OID []byte
    13  
    14  func init() {
    15  	krb5OID, _ = asn1.Marshal(krb5Mesh)
    16  }
    17  
    18  // GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins.
    19  type GSSAPIClient interface {
    20  	// InitSecContext initiates the establishment of a security context for GSS-API between the
    21  	// ssh client and ssh server. Initially the token parameter should be specified as nil.
    22  	// The routine may return a outputToken which should be transferred to
    23  	// the ssh server, where the ssh server will present it to
    24  	// AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting
    25  	// needContinue to false. To complete the context
    26  	// establishment, one or more reply tokens may be required from the ssh
    27  	// server;if so, InitSecContext will return a needContinue which is true.
    28  	// In this case, InitSecContext should be called again when the
    29  	// reply token is received from the ssh server, passing the reply
    30  	// token to InitSecContext via the token parameters.
    31  	// See RFC 2743 section 2.2.1 and RFC 4462 section 3.4.
    32  	InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error)
    33  	// GetMIC generates a cryptographic MIC for the SSH2 message, and places
    34  	// the MIC in a token for transfer to the ssh server.
    35  	// The contents of the MIC field are obtained by calling GSS_GetMIC()
    36  	// over the following, using the GSS-API context that was just
    37  	// established:
    38  	//  string    session identifier
    39  	//  byte      SSH_MSG_USERAUTH_REQUEST
    40  	//  string    user name
    41  	//  string    service
    42  	//  string    "gssapi-with-mic"
    43  	// See RFC 2743 section 2.3.1 and RFC 4462 3.5.
    44  	GetMIC(micFiled []byte) ([]byte, error)
    45  	// Whenever possible, it should be possible for
    46  	// DeleteSecContext() calls to be successfully processed even
    47  	// if other calls cannot succeed, thereby enabling context-related
    48  	// resources to be released.
    49  	// In addition to deleting established security contexts,
    50  	// gss_delete_sec_context must also be able to delete "half-built"
    51  	// security contexts resulting from an incomplete sequence of
    52  	// InitSecContext()/AcceptSecContext() calls.
    53  	// See RFC 2743 section 2.2.3.
    54  	DeleteSecContext() error
    55  }
    56  
    57  // GSSAPIServer provides the API to plug in GSSAPI authentication for server logins.
    58  type GSSAPIServer interface {
    59  	// AcceptSecContext allows a remotely initiated security context between the application
    60  	// and a remote peer to be established by the ssh client. The routine may return a
    61  	// outputToken which should be transferred to the ssh client,
    62  	// where the ssh client will present it to InitSecContext.
    63  	// If no token need be sent, AcceptSecContext will indicate this
    64  	// by setting the needContinue to false. To
    65  	// complete the context establishment, one or more reply tokens may be
    66  	// required from the ssh client. if so, AcceptSecContext
    67  	// will return a needContinue which is true, in which case it
    68  	// should be called again when the reply token is received from the ssh
    69  	// client, passing the token to AcceptSecContext via the
    70  	// token parameters.
    71  	// The srcName return value is the authenticated username.
    72  	// See RFC 2743 section 2.2.2 and RFC 4462 section 3.4.
    73  	AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error)
    74  	// VerifyMIC verifies that a cryptographic MIC, contained in the token parameter,
    75  	// fits the supplied message is received from the ssh client.
    76  	// See RFC 2743 section 2.3.2.
    77  	VerifyMIC(micField []byte, micToken []byte) error
    78  	// Whenever possible, it should be possible for
    79  	// DeleteSecContext() calls to be successfully processed even
    80  	// if other calls cannot succeed, thereby enabling context-related
    81  	// resources to be released.
    82  	// In addition to deleting established security contexts,
    83  	// gss_delete_sec_context must also be able to delete "half-built"
    84  	// security contexts resulting from an incomplete sequence of
    85  	// InitSecContext()/AcceptSecContext() calls.
    86  	// See RFC 2743 section 2.2.3.
    87  	DeleteSecContext() error
    88  }
    89  
    90  var (
    91  	// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,
    92  	// so we also support the krb5 mechanism only.
    93  	// See RFC 1964 section 1.
    94  	krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
    95  )
    96  
    97  // The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST
    98  // See RFC 4462 section 3.2.
    99  type userAuthRequestGSSAPI struct {
   100  	N    uint32
   101  	OIDS []asn1.ObjectIdentifier
   102  }
   103  
   104  func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
   105  	n, rest, ok := parseUint32(payload)
   106  	if !ok {
   107  		return nil, errors.New("parse uint32 failed")
   108  	}
   109  	s := &userAuthRequestGSSAPI{
   110  		N:    n,
   111  		OIDS: make([]asn1.ObjectIdentifier, n),
   112  	}
   113  	for i := 0; i < int(n); i++ {
   114  		var (
   115  			desiredMech []byte
   116  			err         error
   117  		)
   118  		desiredMech, rest, ok = parseString(rest)
   119  		if !ok {
   120  			return nil, errors.New("parse string failed")
   121  		}
   122  		if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
   123  			return nil, err
   124  		}
   125  
   126  	}
   127  	return s, nil
   128  }
   129  
   130  // See RFC 4462 section 3.6.
   131  func buildMIC(sessionID string, username string, service string, authMethod string) []byte {
   132  	out := make([]byte, 0, 0)
   133  	out = appendString(out, sessionID)
   134  	out = append(out, msgUserAuthRequest)
   135  	out = appendString(out, username)
   136  	out = appendString(out, service)
   137  	out = appendString(out, authMethod)
   138  	return out
   139  }