Skip to content

golang-auth/go-gssapi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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/golang-auth/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
  • Channel binding (for initators)

The following functionality is currently not available:

  • GSS-API v1 message tokens (RFC1964)
  • Delegation
  • Acceptor 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/golang-auth/go-gssapi/v2"
  package main

  //  register the Kerberos GSS-API mechsnism
  import _ "github.com/golang-auth/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/golang-auth/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/golang-auth/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, nil)

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.