Skip to content

Commit ef4ea14

Browse files
committed
feat: Add GSS-TSIG server functionality
1 parent 0d4e7fc commit ef4ea14

10 files changed

Lines changed: 804 additions & 81 deletions

File tree

gss/apcera.go

Lines changed: 204 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,54 @@ import (
1717
"github.com/openshift/gssapi"
1818
)
1919

20+
func generate(lib *gssapi.Lib, ctx *gssapi.CtxId, msg []byte) ([]byte, error) {
21+
message, err := lib.MakeBufferBytes(msg)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
defer func() {
27+
err = multierror.Append(err, message.Release()).ErrorOrNil()
28+
}()
29+
30+
token, err := ctx.GetMIC(gssapi.GSS_C_QOP_DEFAULT, message)
31+
if err != nil {
32+
return nil, err
33+
}
34+
35+
defer func() {
36+
err = multierror.Append(err, token.Release()).ErrorOrNil()
37+
}()
38+
39+
return token.Bytes(), nil
40+
}
41+
42+
func verify(lib *gssapi.Lib, ctx *gssapi.CtxId, stripped, mac []byte) error {
43+
message, err := lib.MakeBufferBytes(stripped)
44+
if err != nil {
45+
return err
46+
}
47+
48+
defer func() {
49+
err = multierror.Append(err, message.Release()).ErrorOrNil()
50+
}()
51+
52+
token, err := lib.MakeBufferBytes(mac)
53+
if err != nil {
54+
return err
55+
}
56+
57+
defer func() {
58+
err = multierror.Append(err, token.Release()).ErrorOrNil()
59+
}()
60+
61+
if _, err = ctx.VerifyMIC(message, token); err != nil {
62+
return err
63+
}
64+
65+
return nil
66+
}
67+
2068
// Client maps the TKEY name to the context that negotiated it as
2169
// well as any other internal state.
2270
type Client struct {
@@ -28,16 +76,14 @@ type Client struct {
2876
}
2977

3078
// WithConfig sets the Kerberos configuration used.
31-
func WithConfig(_ string) func(*Client) error {
32-
return func(c *Client) error {
33-
return errNotSupported
34-
}
79+
func WithConfig[T Client](_ string) Option[T] {
80+
return unsupportedOption[T]
3581
}
3682

3783
// NewClient performs any library initialization necessary.
3884
// It returns a context handle for any further functions along with any error
3985
// that occurred.
40-
func NewClient(dnsClient *dns.Client, options ...func(*Client) error) (*Client, error) {
86+
func NewClient(dnsClient *dns.Client, options ...Option[Client]) (*Client, error) {
4187
client, err := util.CopyDNSClient(dnsClient)
4288
if err != nil {
4389
return nil, err
@@ -57,8 +103,10 @@ func NewClient(dnsClient *dns.Client, options ...func(*Client) error) (*Client,
57103
logger: logr.Discard(),
58104
}
59105

60-
if err := c.setOption(options...); err != nil {
61-
return nil, multierror.Append(err, c.lib.Unload())
106+
for _, option := range options {
107+
if err := option(c); err != nil {
108+
return nil, multierror.Append(err, c.lib.Unload())
109+
}
62110
}
63111

64112
return c, nil
@@ -72,54 +120,11 @@ func (c *Client) Close() error {
72120
}
73121

74122
func (c *Client) generate(ctx *gssapi.CtxId, msg []byte) ([]byte, error) {
75-
message, err := c.lib.MakeBufferBytes(msg)
76-
if err != nil {
77-
return nil, err
78-
}
79-
80-
defer func() {
81-
err = multierror.Append(err, message.Release()).ErrorOrNil()
82-
}()
83-
84-
token, err := ctx.GetMIC(gssapi.GSS_C_QOP_DEFAULT, message)
85-
if err != nil {
86-
return nil, err
87-
}
88-
89-
defer func() {
90-
err = multierror.Append(err, token.Release()).ErrorOrNil()
91-
}()
92-
93-
return token.Bytes(), nil
123+
return generate(c.lib, ctx, msg)
94124
}
95125

96126
func (c *Client) verify(ctx *gssapi.CtxId, stripped, mac []byte) error {
97-
// Turn the TSIG-stripped message bytes into a *gssapi.Buffer
98-
message, err := c.lib.MakeBufferBytes(stripped)
99-
if err != nil {
100-
return err
101-
}
102-
103-
defer func() {
104-
err = multierror.Append(err, message.Release()).ErrorOrNil()
105-
}()
106-
107-
// Turn the TSIG MAC bytes into a *gssapi.Buffer
108-
token, err := c.lib.MakeBufferBytes(mac)
109-
if err != nil {
110-
return err
111-
}
112-
113-
defer func() {
114-
err = multierror.Append(err, token.Release()).ErrorOrNil()
115-
}()
116-
117-
// This is the actual verification bit
118-
if _, err = ctx.VerifyMIC(message, token); err != nil {
119-
return err
120-
}
121-
122-
return nil
127+
return verify(c.lib, ctx, stripped, mac)
123128
}
124129

125130
// NegotiateContext exchanges RFC 2930 TKEY records with the indicated DNS
@@ -258,3 +263,150 @@ func (c *Client) DeleteContext(keyname string) error {
258263

259264
return nil
260265
}
266+
267+
// Server maps the TKEY name to the context that negotiated it as
268+
// well as any other internal state.
269+
type Server struct {
270+
m sync.RWMutex
271+
lib *gssapi.Lib
272+
ctx map[string]*gssapi.CtxId
273+
logger logr.Logger
274+
}
275+
276+
// NewServer performs any library initialization necessary.
277+
// It returns a context handle for any further functions along with any error
278+
// that occurred.
279+
func NewServer(options ...Option[Server]) (*Server, error) {
280+
lib, err := gssapi.Load(nil)
281+
if err != nil {
282+
return nil, err
283+
}
284+
285+
s := &Server{
286+
lib: lib,
287+
ctx: make(map[string]*gssapi.CtxId),
288+
logger: logr.Discard(),
289+
}
290+
291+
for _, option := range options {
292+
if err := option(s); err != nil {
293+
return nil, multierror.Append(err, s.lib.Unload())
294+
}
295+
}
296+
297+
return s, nil
298+
}
299+
300+
// Close deletes any active contexts and unloads any underlying libraries as
301+
// necessary.
302+
// It returns any error that occurred.
303+
func (s *Server) Close() error {
304+
return multierror.Append(s.close(true), s.lib.Unload()).ErrorOrNil()
305+
}
306+
307+
func (s *Server) newContext() (*gssapi.CtxId, error) {
308+
//nolint:nilnil
309+
return nil, nil
310+
}
311+
312+
//nolint:funlen
313+
func (s *Server) update(ctx *gssapi.CtxId, input []byte) (*gssapi.CtxId, []byte, error) {
314+
/*var cred *gssapi.CredId
315+
316+
// equivalent of GSSAPIStrictAcceptorCheck
317+
if s.strict { //nolint:nestif
318+
hostname, err := osHostname()
319+
if err != nil {
320+
return nil, "", false, err
321+
}
322+
323+
buffer, err := s.lib.MakeBufferString("host@" + hostname)
324+
if err != nil {
325+
return nil, "", false, err
326+
}
327+
328+
defer func() {
329+
err = multierror.Append(err, buffer.Release()).ErrorOrNil()
330+
}()
331+
332+
service, err := buffer.Name(s.lib.GSS_C_NT_HOSTBASED_SERVICE)
333+
if err != nil {
334+
return nil, "", false, err
335+
}
336+
337+
defer func() {
338+
err = multierror.Append(err, service.Release()).ErrorOrNil()
339+
}()
340+
341+
oids, err := s.lib.MakeOIDSet(s.lib.GSS_MECH_KRB5)
342+
if err != nil {
343+
return nil, "", false, err
344+
}
345+
346+
defer func() {
347+
err = multierror.Append(err, oids.Release()).ErrorOrNil()
348+
}()
349+
350+
cred, _, _, err = s.lib.AcquireCred(service, gssapi.GSS_C_INDEFINITE, oids, gssapi.GSS_C_ACCEPT)
351+
if err != nil {
352+
return nil, "", false, err
353+
}
354+
355+
defer func() {
356+
err = multierror.Append(err, cred.Release()).ErrorOrNil()
357+
}()
358+
} else {*/
359+
cred := s.lib.GSS_C_NO_CREDENTIAL
360+
//}
361+
362+
token, err := s.lib.MakeBufferBytes(input)
363+
if err != nil {
364+
return nil, nil, err
365+
}
366+
367+
defer func() {
368+
err = multierror.Append(err, token.Release()).ErrorOrNil()
369+
}()
370+
371+
//nolint:dogsled
372+
nctx, _, _, output, _, _, _, err := s.lib.AcceptSecContext(ctx, cred, token, s.lib.GSS_C_NO_CHANNEL_BINDINGS)
373+
if err != nil && !s.lib.LastStatus.Major.ContinueNeeded() {
374+
return nil, nil, err
375+
}
376+
377+
defer func() {
378+
err = multierror.Append(err, output.Release()).ErrorOrNil()
379+
}()
380+
381+
return nctx, output.Bytes(), nil
382+
}
383+
384+
func (s *Server) generate(ctx *gssapi.CtxId, msg []byte) ([]byte, error) {
385+
return generate(s.lib, ctx, msg)
386+
}
387+
388+
func (s *Server) verify(ctx *gssapi.CtxId, stripped, mac []byte) error {
389+
return verify(s.lib, ctx, stripped, mac)
390+
}
391+
392+
func (s *Server) established(ctx *gssapi.CtxId) (established bool, err error) {
393+
if ctx != nil {
394+
_, _, _, _, _, _, established, err = ctx.InquireContext()
395+
}
396+
397+
return
398+
}
399+
400+
func (s *Server) expired(ctx *gssapi.CtxId) (expired bool, err error) {
401+
if ctx != nil {
402+
var duration time.Duration
403+
_, _, duration, _, _, _, _, err = ctx.InquireContext()
404+
expired = duration <= 0
405+
}
406+
407+
return
408+
}
409+
410+
func (s *Server) delete(ctx *gssapi.CtxId) error {
411+
return ctx.DeleteSecContext()
412+
}

gss/apcera_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,11 @@ func TestNewClientWithConfig(t *testing.T) {
2929
_, err := gss.NewClient(new(dns.Client), gss.WithConfig(""))
3030
assert.NotNil(t, err)
3131
}
32+
33+
func TestNewServer(t *testing.T) {
34+
t.Parallel()
35+
36+
if err := testNewServer(t); err != nil {
37+
t.Fatal(err)
38+
}
39+
}

gss/client.go

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ func (c *Client) close() error {
6868

6969
c.m.RUnlock()
7070

71-
var errs error
71+
var err *multierror.Error
7272
for _, k := range keys {
73-
errs = multierror.Append(errs, c.DeleteContext(k))
73+
err = multierror.Append(err, c.DeleteContext(k))
7474
}
7575

76-
return errs
76+
return err.ErrorOrNil()
7777
}
7878

7979
func (c *Client) setOption(options ...func(*Client) error) error {
@@ -87,20 +87,15 @@ func (c *Client) setOption(options ...func(*Client) error) error {
8787
}
8888

8989
// SetConfig sets the Kerberos configuration used by c.
90+
//
91+
// Deprecated: FIXME.
9092
func (c *Client) SetConfig(config string) error {
9193
return c.setOption(WithConfig(config))
9294
}
9395

94-
// WithLogger sets the logger used.
95-
func WithLogger(logger logr.Logger) func(*Client) error {
96-
return func(c *Client) error {
97-
c.logger = logger.WithName("client")
98-
99-
return nil
100-
}
101-
}
102-
10396
// SetLogger sets the logger used by c.
97+
//
98+
// Deprecated: FIXME.
10499
func (c *Client) SetLogger(logger logr.Logger) error {
105-
return c.setOption(WithLogger(logger))
100+
return c.setOption(WithLogger[Client](logger))
106101
}

0 commit comments

Comments
 (0)