ssh_gss.go (5570B)
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 }