forked from go-ldap/ldap
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgssapi.go
130 lines (104 loc) · 2.64 KB
/
gssapi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package ldap
import (
"fmt"
"github.com/jcmturner/gokrb5/v8/client"
"github.com/jcmturner/gokrb5/v8/crypto"
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
"github.com/jcmturner/gokrb5/v8/messages"
"github.com/jcmturner/gokrb5/v8/types"
"github.com/jcmturner/gokrb5/v8/gssapi"
"github.com/jcmturner/gokrb5/v8/spnego"
)
type GSSAPIState struct {
AuthZID string
token spnego.KRB5Token
ekey types.EncryptionKey
Subkey types.EncryptionKey
init bool
asrep bool
}
func InitContext(client *client.Client, principal, AuthZID string) (*GSSAPIState, error) {
tkt, ekey, err := client.GetServiceTicket(principal)
if err != nil {
return nil, err
}
token, err := spnego.NewKRB5TokenAPREQ(client, tkt, ekey, []int{gssapi.ContextFlagInteg, gssapi.ContextFlagConf, gssapi.ContextFlagMutual}, []int{})
if err != nil {
return nil, err
}
state := &GSSAPIState{
AuthZID: AuthZID,
ekey: ekey,
token: token,
init: false,
asrep: false,
}
return state, nil
}
func (state *GSSAPIState) GSSAPIStep(input []byte) ([]byte, error) {
if !state.init {
state.init = true
return state.token.Marshal()
}
if !state.asrep {
err := state.token.Unmarshal(input)
if err != nil {
return nil, err
}
if state.token.IsAPRep() {
state.asrep = true
encpart, err := crypto.DecryptEncPart(state.token.APRep.EncPart, state.ekey, keyusage.AP_REP_ENCPART)
if err != nil {
return nil, err
}
part := &messages.EncAPRepPart{}
err = part.Unmarshal(encpart)
if err != nil {
return nil, err
}
state.Subkey = part.Subkey
}
if state.token.IsKRBError() {
return nil, state.token.KRBError
}
return make([]byte, 0), nil
}
token := &gssapi.WrapToken{}
err := token.Unmarshal(input, true)
if err != nil {
return nil, err
}
if (token.Flags & 0b1) == 0 {
return nil, fmt.Errorf("Got a Wrapped token that's not from the server")
}
key := state.ekey
if (token.Flags & 0b100) != 0 {
key = state.Subkey
}
_, err = token.Verify(key, keyusage.GSSAPI_ACCEPTOR_SEAL)
if err != nil {
return nil, err
}
pl := token.Payload
if len(pl) != 4 {
return nil, fmt.Errorf("Server send bad final token for SASL GSSAPI Handshake")
}
// We never want a security layer
b := [4]byte{0, 0, 0, 0}
payload := append(b[:], []byte(state.AuthZID)...)
encType, err := crypto.GetEtype(key.KeyType)
if err != nil {
return nil, err
}
token = &gssapi.WrapToken{
Flags: 0b100,
EC: uint16(encType.GetHMACBitLength() / 8),
RRC: 0,
SndSeqNum: 1,
Payload: payload,
}
if err := token.SetCheckSum(key, keyusage.GSSAPI_INITIATOR_SEAL); err != nil {
return nil, err
}
return token.Marshal()
}