forked from jcmturner/gokrb5
-
Notifications
You must be signed in to change notification settings - Fork 0
/
krb5Token.go
201 lines (186 loc) · 5.51 KB
/
krb5Token.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package gssapi
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"github.com/jcmturner/gofork/encoding/asn1"
"gopkg.in/jcmturner/gokrb5.v4/asn1tools"
"gopkg.in/jcmturner/gokrb5.v4/credentials"
"gopkg.in/jcmturner/gokrb5.v4/iana/chksumtype"
"gopkg.in/jcmturner/gokrb5.v4/krberror"
"gopkg.in/jcmturner/gokrb5.v4/messages"
"gopkg.in/jcmturner/gokrb5.v4/types"
)
// GSSAPI MechToken IDs and flags.
const (
TOK_ID_KRB_AP_REQ = "0100"
TOK_ID_KRB_AP_REP = "0200"
TOK_ID_KRB_ERROR = "0300"
GSS_C_DELEG_FLAG = 1
GSS_C_MUTUAL_FLAG = 2
GSS_C_REPLAY_FLAG = 4
GSS_C_SEQUENCE_FLAG = 8
GSS_C_CONF_FLAG = 16
GSS_C_INTEG_FLAG = 32
)
// MechToken implementation for GSSAPI.
type MechToken struct {
OID asn1.ObjectIdentifier
TokID []byte
APReq messages.APReq
APRep messages.APRep
KRBError messages.KRBError
}
// Marshal a MechToken into a slice of bytes.
func (m *MechToken) Marshal() ([]byte, error) {
// Create the header
b, _ := asn1.Marshal(m.OID)
b = append(b, m.TokID...)
var tb []byte
var err error
switch hex.EncodeToString(m.TokID) {
case TOK_ID_KRB_AP_REQ:
tb, err = m.APReq.Marshal()
if err != nil {
return []byte{}, fmt.Errorf("error marshalling AP_REQ for MechToken: %v", err)
}
case TOK_ID_KRB_AP_REP:
return []byte{}, errors.New("marshal of AP_REP GSSAPI MechToken not supported by gokrb5")
case TOK_ID_KRB_ERROR:
return []byte{}, errors.New("marshal of KRB_ERROR GSSAPI MechToken not supported by gokrb5")
}
if err != nil {
return []byte{}, fmt.Errorf("error mashalling kerberos message within mech token: %v", err)
}
b = append(b, tb...)
return asn1tools.AddASNAppTag(b, 0), nil
}
// Unmarshal a MechToken.
func (m *MechToken) Unmarshal(b []byte) error {
var oid asn1.ObjectIdentifier
r, err := asn1.UnmarshalWithParams(b, &oid, fmt.Sprintf("application,explicit,tag:%v", 0))
if err != nil {
return fmt.Errorf("Error unmarshalling MechToken OID: %v", err)
}
m.OID = oid
m.TokID = r[0:2]
switch hex.EncodeToString(m.TokID) {
case TOK_ID_KRB_AP_REQ:
var a messages.APReq
err = a.Unmarshal(r[2:])
if err != nil {
return fmt.Errorf("Error unmarshalling MechToken AP_REQ: %v", err)
}
m.APReq = a
case TOK_ID_KRB_AP_REP:
var a messages.APRep
err = a.Unmarshal(r[2:])
if err != nil {
return fmt.Errorf("Error unmarshalling MechToken AP_REP: %v", err)
}
m.APRep = a
case TOK_ID_KRB_ERROR:
var a messages.KRBError
err = a.Unmarshal(r[2:])
if err != nil {
return fmt.Errorf("Error unmarshalling MechToken KRBError: %v", err)
}
m.KRBError = a
}
return nil
}
// IsAPReq tests if the MechToken contains an AP_REQ.
func (m *MechToken) IsAPReq() bool {
if hex.EncodeToString(m.TokID) == TOK_ID_KRB_AP_REQ {
return true
}
return false
}
// IsAPRep tests if the MechToken contains an AP_REP.
func (m *MechToken) IsAPRep() bool {
if hex.EncodeToString(m.TokID) == TOK_ID_KRB_AP_REP {
return true
}
return false
}
// IsKRBError tests if the MechToken contains an KRB_ERROR.
func (m *MechToken) IsKRBError() bool {
if hex.EncodeToString(m.TokID) == TOK_ID_KRB_ERROR {
return true
}
return false
}
// NewAPREQMechToken creates new Kerberos AP_REQ MechToken.
func NewAPREQMechToken(creds credentials.Credentials, tkt messages.Ticket, sessionKey types.EncryptionKey, GSSAPIFlags []int, APOptions []int) (MechToken, error) {
var m MechToken
m.OID = MechTypeOIDKRB5
tb, _ := hex.DecodeString(TOK_ID_KRB_AP_REQ)
m.TokID = tb
auth, err := NewAuthenticator(creds, GSSAPIFlags)
if err != nil {
return m, err
}
APReq, err := messages.NewAPReq(
tkt,
sessionKey,
auth,
)
if err != nil {
return m, err
}
for _, o := range APOptions {
types.SetFlag(&APReq.APOptions, o)
}
m.APReq = APReq
return m, nil
}
// NewAuthenticator creates a new kerberos authenticator for kerberos MechToken
func NewAuthenticator(creds credentials.Credentials, flags []int) (types.Authenticator, error) {
//RFC 4121 Section 4.1.1
auth, err := types.NewAuthenticator(creds.Realm, creds.CName)
if err != nil {
return auth, krberror.Errorf(err, krberror.KRBMsgError, "error generating new authenticator")
}
auth.Cksum = types.Checksum{
CksumType: chksumtype.GSSAPI,
Checksum: newAuthenticatorChksum(flags),
}
return auth, nil
}
// Create new authenticator checksum for kerberos MechToken
func newAuthenticatorChksum(flags []int) []byte {
a := make([]byte, 24)
binary.LittleEndian.PutUint32(a[:4], 16)
for _, i := range flags {
if i == GSS_C_DELEG_FLAG {
x := make([]byte, 28-len(a))
a = append(a, x...)
}
f := binary.LittleEndian.Uint32(a[20:24])
f |= uint32(i)
binary.LittleEndian.PutUint32(a[20:24], f)
}
return a
}
/*
The authenticator checksum field SHALL have the following format:
Octet Name Description
-----------------------------------------------------------------
0..3 Lgth Number of octets in Bnd field; Represented
in little-endian order; Currently contains
hex value 10 00 00 00 (16).
4..19 Bnd Channel binding information, as described in
section 4.1.1.2.
20..23 Flags Four-octet context-establishment flags in
little-endian order as described in section
4.1.1.1.
24..25 DlgOpt The delegation option identifier (=1) in
little-endian order [optional]. This field
and the next two fields are present if and
only if GSS_C_DELEG_FLAG is set as described
in section 4.1.1.1.
26..27 Dlgth The length of the Deleg field in little-endian order [optional].
28..(n-1) Deleg A KRB_CRED message (n = Dlgth + 28) [optional].
n..last Exts Extensions [optional].
*/