Skip to content

Commit b66a271

Browse files
committed
feat: Add GSS-TSIG server functionality
1 parent 307c426 commit b66a271

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
@@ -260,3 +265,150 @@ func (c *Client) DeleteContext(keyname string) error {
260265

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

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)