gssapi

package module
v2.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2022 License: Apache-2.0 Imports: 1 Imported by: 0

README

go-gssapi: pure Go GSS-API implementation

GitHub tag (latest SemVer) Git Workflow Go Version PkgGoDev

go-gssapi is a pure Golang implementation of the GSS-API version 2 specification (RFC 2743). It uses the pure Golang Kerberos implementation to obtain Kerberos tickets and perform cryptographic operations.

Documentation at https://pkg.go.dev/github.com/jake-scott/go-gssapi/v2

Implemented functionality

The current version implements the Kerberos V5 authentication mechanism (RFC 4121) We plan to support SPNEGO in a future release.

The following features are currently available:

  • Initiator (client) and Acceptor (server)
  • Mutual authentication
  • Message Integrity and Confidentiality
  • GSS MIC and Wrap tokens
  • Basic support for detecting out-of-sequence and duplicate messages

The following functionality is currently not available:

  • GSS-API v1 message tokens (RFC1964)
  • Delegation
  • Channel binding

Platforms

Currently Unix platforms. Support for the Windows SSPI will be added in future.

Project status

go-gssapi is not yet considered to be production ready, and the interface is not yet considered stable. We started at v2 to support the new Go versioning standrd. A v2.0.0 tag will be created after which we will follow normal semantic versioning conventions.

Configuration

The Kerberos implementiaton behing the GSS-API functionality is hidden form the caller. The name of the krb5.conf file, credential cache (by an Initiator) and keytab file (by an Acceptor) are identified from the environment or using default paths if not specified in the environment :

Configuration item Environment variable Default
Kerberos client configuartion file KRB5_CONFIG /etc/krb5.conf
Credential cache file KRB5CCNAME /etc/krb5cc_%{UID}
Keytab file KRB5_KTNAME /var/kerberos/krb5/user/%{UID}/client.keytab

.. where %{UID} is the current username as returned by id -u

💧 A future releaes will choose defaults based on the platform we're running on, and may provide more complete control of the gokrb client. Please file a new Github issue if you have a use-case.

Import paths and versions

Import the base go-gssapi package where you will use GSS-API, and the mechanism specific package somewhere (usually the main package) to register the mechanism :

  package myclient
  
  import "github.com/jake-scott/go-gssapi/v2"
  package main

  //  register the Kerberos GSS-API mechsnism
  import _ "github.com/jake-scott/go-gssapi/v2/krb5"

We will maintain major versions of the library in separate Git branches. To use the latest version in a branch, use go get with the branch name, eg :

 go get github.com/jake-scott/go-gssapi/v2@v2.0.0-alpha

This will result in a concrete version being added to go.mod:

module test

go 1.15

require github.com/jake-scott/go-gssapi/v2 v2.0.0-alpha //indirect

Initialization

Obtain an instance (context) of a mechanism-specif implementation:

  ctx := gssapi.NewMech("kerberos_v5)

then configure the context as an Initiator (client):

  service := "ldap/ldap.example.com"
  var flags gssapi.ContextFlag = gssapi.ContextFlagInteg |
                                 gssapi.ContextFlagConf |
                                 gssapi.ContextFlagReplay |
                                 gssapi.ContextFlagSequence |
                                 gssapi.ContextFlagMutual
  err := ctx.Initiate(service, flags)

or Acceptor (server):

  err := ctx.Accept("")

Note: go-gssapi uses the Kebreros V5 principal name format (primary/instance), not the NT_HOSTBASED_SERVICE format (service@host) used by other GSS-API implementations

Negotiation loop

Once the context is initialized as an Initiator or Acceptor, the client and server enter a loop until IsEstablished returns true. Each pass through the loop, the Continue method is called on the context. Continue may return an opaque token that should be sent to the peer. The peer passes the token to the Continue method and the process is repeated.

Initiator loop
var inToken, outToken []byte

for !ctx.IsEstablished() {
   outToken, err = ctx.Continue(inToken)
   if err != nil {
       break
   }

   if len(outToken) > 0 {
       if sendErr := sendToken(conn, outToken); sendErr != nil {
               err = sendErr
               break
       }
   }

   if !ctx.IsEstablished() {
       inToken, err = recvToken(conn)
       if err != nil {
           break
       }
   }
}

if err != nil {
   fmt.Fprintln(os.Stderr, err)
   os.Exit(1)
}
Acceptor loop
var inToken, outToken []byte

for !ctx.IsEstablished() {
    inToken, err = recvToken(conn)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        break
    }

    outToken, err = ctx.Continue(inToken)
    if len(outToken) > 0 {
        if sendErr := sendToken(conn, outToken); sendErr != nil {
            err = sendErr
            break
        }
    }
}

if err != nil {
    fmt.Fprintln(os.Stderr, err)
    return
}

Exchanging messages

GSS-API defines two message types :

  • Wrap messages encapsulate a message payload plus either a signature, or with the payload encrypted (if confidentially is requested)
  • Message Integrity Code (MIC) messages convey a signature of a payload but do not encapsulate the actual payload

The context Wrap and MakeSignature methods are used to generate serialized GSS-API message tokens for a given payload. MIC tokens can be communicated separately from the payload, for example as a part of an acknowledgement or via a separate channel from the data.

The receiver of a message passes the token to the context Unwrap and VerifySignature methods. Unwrap verifies the message payload signature or decrypts the message payload (if confidentially is in use). VerifySignature verifies the signature of a payload passed to the method.

sender

msg := "Hello go-gssapi!"
seal := true  // ask for confidentiality

// Wrap the message
outToken, err = ctx.Wrap([]byte(msg), seal)
if err != nil {
  return err
}

// send it to the GSS-API peer
if err = sendToken(conn, outToken); err != nil {
  retirm err
}

receiver
inToken, err := recvToken(conn)
if err != nil {
  return err
}

msg, isSealed, err := ctx.Unwrap(inToken)
if err != nil {
    return err
}

protStr := "signed"
if isSealed {
        protStr = "sealed"
}
fmt.Printf(`Received %s message: "%s"`+"\n", protStr, msg)

Sample code

Examples implemented in C (for use with the MIT or Heimdal GSS-API library) and Go are included in the examples directory. The C samples are provided to demonstrate go-gssapi interoperatbility.

Documentation

Overview

Package gssapi provides a Go interface to the Generic Security Services Application Program Interface.

The package defines an interface that GSS-API mechanism specific code should conform to.

An Initiator (ie. client) uses the Initiate method to start the authentiation process. An Acceptor (ie. server) uses the Accpet method instead. After that, both sides call Continue in a loop, transferring token between themselves using a suitable communication protocol. When IsEstablished returns true, the security context can be used to securely transfer messages or message signatures using Wrap/Unwrap or MakeSignature/VerifySignature.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FlagName

func FlagName(f ContextFlag) string

FlagName returns a human-readable description of a context flag value

func IsRegistered

func IsRegistered(name string) bool

IsRegistered can be used to find out whether a named mechanism is registered or not

func Mechs

func Mechs() (l []string)

Mechs returns the list of registered mechanism names

func Register

func Register(name string, f MechFactory)

Register should be called by Mech implementations to enable a mechanism to be used by clients

Types

type ContextFlag

type ContextFlag uint32
const (
	ContextFlagDeleg    ContextFlag = 1 << iota // delegate credentials, not currently supported
	ContextFlagMutual                           // request remote peer authenticates itself
	ContextFlagReplay                           // enable replay detection for signed/sealed messages
	ContextFlagSequence                         // enable detection of out of sequence signed/sealed messages
	ContextFlagConf                             // confidentiality available
	ContextFlagInteg                            // integrity available
)

GSS-API context flags assigned numbers.

func FlagList

func FlagList(f ContextFlag) (fl []ContextFlag)

FlagList returns a slice of individual flags derived from the composite value f

type Mech

type Mech interface {
	// IsEstablished can be used to determine whether the security
	// context between an Initiator and Acceptor is complete and
	// is ready to transfer messages between the peers.
	IsEstablished() bool

	// ContextFlags returns the security flags negotiated between
	// the initiator and acceptor.  The flags *SHOULD* be checked
	// before using the context to verify that desired security
	// requirements have been met.
	ContextFlags() ContextFlag

	// PeerName returns a string representingg the peer's identity
	PeerName() string

	// Initiate is used by a GSS-API Initiator to start the
	// context negotiation process with a remote Acceptor.
	// serverName is the mechanism specific name of the remote
	// Acceptor, and flags represent the desired security
	// properties of the context.
	Initiate(serviceName string, flags ContextFlag) (err error)

	InitiateByCreds(serviceName string, flags ContextFlag, username string, domain string, password string) (err error)

	// Accept is used by a GSS-API Acceptor to begin context
	// negotiation with a remote Initiator.
	// If provided, serviceName is the mechanism specific identifier
	// of the local Acceptor
	Accept(serviceName string) (err error)

	// Continue is called in a loop by Initiators and Acceptors after
	// first calling one of Initiate or Accept.
	// tokenIn represents a token received from the peer
	// If tokenOut is non-zero, it should be send to the peer
	Continue(tokenIn []byte) (tokenOut []byte, err error)

	// Wrap is called by either peer after the context is establighed
	// to create a token that encapsulates a payload.  If confidentially
	// is required, the payload is encrypted (*sealed*) using a key
	// negotiated during context establishment.  Otherwise, the key
	// is used to sign the payload which is encapsulated in the clear.
	// tokenOut should be communicated to the peer which should use Unwrap
	// on the token.
	Wrap(tokenIn []byte, confidentiality bool) (tokenOut []byte, err error)

	// Unwrap is passed a wrap token received from a peer.  If the token
	// provides confidentially, the key negotiated during context establishment
	// is used to decrypt (*unseal*) the payload.  Otherwise, the key is used
	// to verify the signature that the remote Wrap call calculated for the
	// payload.
	// tokenOut is the original payload
	// isSealed conveys whether the payload was encrypted or not
	Unwrap(tokenIn []byte) (tokenOut []byte, isSealed bool, err error)

	// MakeSignature creates a token that includes the signature of the
	// provided payload but does not include the payload itself.  The
	// output token should be sent to the peer, which should use its copy of
	// the payload (communicated separately) to verify the signature.
	MakeSignature(payload []byte) (tokenOut []byte, err error)

	// VerifySignature is used to check the signature received from a peer
	// using a local copy of the payloads.
	VerifySignature(payload []byte, tokenIn []byte) (err error)
}

Mech defines the interface to a GSS-API mechanism

func NewMech

func NewMech(name string) Mech

NewMech returns a mechanism context by name

type MechFactory

type MechFactory func() Mech

Directories

Path Synopsis
Package krb5 provides the pure-Go implementation of the GSS-API interface Kerberos mechanism (RFC 4121).
Package krb5 provides the pure-Go implementation of the GSS-API interface Kerberos mechanism (RFC 4121).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL