Skip to content

Golang GSSAPI bindings specification

Jake Scott edited this page Sep 21, 2025 · 11 revisions

THIS IS A WORK IN PROGRESS AN RELATED TO AN UNRELESAED DEV VERSION OF THIS PROJECT

Synopsys

This document outlines a proposed specification for Go language bindings for the GSSAPI Version 2 update 1, as described in the language-neutral RFC 2743.

Although it is not as comprehensive as an RFC, it provides sufficient detail to enable the development of compatible implementations. Generic information about GSSAPI, its features, and usage is not repeated here; refer to other documentation, including the RFCs, for those details.

The specification sets a standard for implementing GSSAPI providers in Go, which can then be used by developers of GSSAPI clients and servers through an interface.

In languages like C, users can select a GSSAPI implementation (provider) during the compilation of the target binary using linker flags (e.g., -lgssapi for Heimdal or -lgssapi_krb5 for MIT).

However, in Go, a provider must be instantiated at compile time. We don't want developers writing GSSAPI clients and servers to hardcode the GSSAPI implementation, as this would defeat the purpose of having an interface. Therefore, the Go specification includes a provider registration interface on top of the functionality described in RFC 2743. This approach is similar to the GSSManager functionality in the Java specification.

The developer of the target binary can load their preferred choice of provider. The ID of the provider is passed to the library that uses GSSAPI, which can instantiate the preferred provider using the registration interface. Library developers can chooses a default provider and allow that choice to be overridden based on user or site preferences or policy.

Provider registration interface

To offer flexibility to developers of target applications, this specification includes a mechanism for provider implementors to register their provider using a unique identifier.

Library developers can instantiate a GSSAPI provider using this identifier. This allows application developers or end users to choose a GSSAPI implementation that meets their application's or site's requirements without modifying any third-party library code.

For example, the developers of an LDAP or HTTP service would write code against the Go GSSAPI interface interface and might select a default GSSAPI provider, such as go-gssapi-c). The developers of applications using these LDAP or HTTP services would then choose a GSSAPI implementation based on their specific needs and arrange for it to be compiled and linked.

The provider registration interface is defined as :

type ProviderFactory func() Provider

func RegisterProvider(name string, f ProviderFactory)

func NewProvider(name string) Provider

GSSAPI providers must register themselves by calling RegisterProvider in their init() function. Providers should document the unique name used in their call to RegisterProvider. This unique name is then used by consumer code to instantiate the desired GSSAPI implementation using the NewProvider method.

Example

This example assumes two Go GSSAPI providers - "MIT" and "Native". The developers of those two implementations would register themselves as such:

[MIT implementation]

import "github.com/golang-auth/go-gssapi/v3"

// advertise this value to consumers of the Provider
const LIBID = "MIT"

func init() {
    gssapi.RegisterProvider(LIBID, New)
}

// implements gssapi.Provider
type Provider struct {}

func New() gssapi.Provider {
    return &Provider{}
}

[Native implementation]

import "github.com/golang-auth/go-gssapi/v3"

// advertise this value to consumers of the Provider
const LIBID = "Native"

func init() {
    gssapi.RegisterProvider(LIBID, New)
}

// implements gssapi.Provider
type Provider struct {}

func New() gssapi.Provider {
    return &Provider{}
}

[library code that uses GSSAPI (say github.com/golang-auth/ldap)]

import "github.com/golang-auth/go-gssapi/v3"

// the developer of the LDAP library specifies MIT as the default provider
var Libname string = "MIT"

type LDAP struct {
        gss gssapi.Provider
}

func New() *LDAP {
    return &LDAP {
        gss: gssapi.NewProvider(Libname)
    }
}

func (l *LDAP) DoThing() error{
  name, err := l.gss.ImportName("foo", gssapi.GSS_KRB5_NT_PRINCIPAL_NAME)
  if err != nil {
        return err
  }
  [...]
}

[Application using github.com/golang-auth/ldap]

package main

import (
    _ "github.com/golang-auth/go-gssapi-native" // load our preferred provider
    "github.com/golang-auth/ldap"
)

// this application prefers the Native GSSAPI provider
var gsslib = "Native"

func main() {
  ldap.Libname = gsslib

  l := ldap.New()
  l.DoThing()
}

The entity compiling the application can choose a custom GSSAPI provider using linker flags, eg:

 go build -ldflags '-X main.gsslib=MY-PROVIDER'

Registration interface

The registry interface is composed of a number of functions exposed by the gssapi package. The import path for the interface is github.com/golang-auth/go-gssapi/v3.

type ProviderFactory func() Provider

The ProviderFactory type defines the function signature passed to RegisterProvider, used by the registration interface to create new instances of a provider.

func RegisterProvider(name string, f ProviderFactory)

The RegisterProvider function associates the supplied provider factory with the unique name for the provider. If a provider with name is already registered, the new factory function will replace the existing registration.

  • Inputs:

    • name : unique name (identifier) of the provider. The author should document this identifier for consumption by users of the provider.
    • f : function that can be used to instantiate the provider
  • Output: None - the function always succeeds

func NewProvider(name string) (p Provider)

NewProvider is used to instantiate a provider given its unique name. It does this by calling the provider factory function registered against the name. The function panics if name is not registered.

  • Inputs:

    • name : unique name of a previously registered provider
  • Output:

    • p : provider instance

GSSAPI interface

Calling Conventions and Data Types

The language-neutral specification defines a set of routines comprising the API. Similar to Java (RFC 2853 § 4), Go offers an environment that eliminates the need for several support calls related to memory management (RFC 2743 § 2.4). Furthermore, Go interfaces encapsulate GSSAPI primitives and the corresponding calls, resulting in a streamlined and idiomatic API familiar to seasoned Go developers. If a provider wraps an existing binding (such as the MIT C binding), it is responsible for managing the memory of temporary buffers. These details should remain hidden from clients using the Go interface.

Integer Types

The GSSAPI specification does not define the size of the INTEGER type used throughout the RFC. In the Go GSSAPI interface specification, the int32 type is used for certain constants such as flags and error codes, mainly for compatibility with C implementations.

The Go interface favors using Go's native time.Time and time.Duration types over integer types that represent lifetimes in seconds since the UNIX epoch.

The RFC does not impose a size limit on messages and buffers (denoted by OCTET STRING in the RFC), and neither does this Go specification. The limit is determined by the integer size on the platform for which the binary is compiled.

It is important to note that some existing GSSAPI implementations (such as the C bindings) do specify a size limit (32 bits in the case of C and Java). Therefore, providers wrapping these implementations MUST return an error if the size of a message exceeds the base implementation's capabilities, rather than allowing a 32-bit integer overflow. Ultimately, it is sensible for applications to impose some limit on message sizes, considering that messages are generally transferred in atomic chunks across the network.

Boolean Type

The native Go bool type is used for boolean values (BOOLEAN in the RFC).

Strings

The native Go string type is used to represent textual data. Go strings include a length, eliminating the need for a separate data structure as used by the C bindings.

Opaque Data Types

Slices of bytes are used to carry opaque data (such as tokens), referred to as OCTET STRING in the RFC. Go slices include a length, removing the need for a separate data structure as specified by the C bindings.

Refer to the comment in the Integer Types section regarding implementations that impose a message size limit.

Object Identifiers (OIDs)

The specification defines the Oid type to represent the OBJECT IDENTIFIER type from the RFC:

type Oid []byte

Elements of the byte slice represent the DER encoding of the object identifier, excluding the ASN.1 header (two bytes: tag value 0x06 and length) as per this Microsoft document.

Other GSSAPI language bindings provide constant OID values for supported mechanisms and names. This specification, however, calls for concrete types for mechanisms and names, along with methods for translating between those types and their associated OIDs (see names). The empty or nil Oid value does not have any special meaning.

Channel Bindings

The Go bindings define the ChannelBinding type to represent channel binding information:

type ChannelBinding struct {
    InitiatorAddr net.Addr
    AcceptorAddr  net.Addr
    Data          []byte
}

type GssAddressFamily int

const (
    GssAddrFamilyUNSPEC GssAddressFamily = iota
    GssAddrFamilyLOCAL
    GssAddrFamilyINET
    GssAddrFamilyIMPLINK
    GssAddrFamilyPUP
    GssAddrFamilyCHAOS
    GssAddrFamilyNS
    GssAddrFamilyNBS
    GssAddrFamilyECMA
    GssAddrFamilyDATAKIT
    GssAddrFamilyCCITT
    GssAddrFamilySNA
    GssAddrFamilyDECnet
    GssAddrFamilyDLI
    GssAddrFamilyLAT
    GssAddrFamilyHYLINK
    GssAddrFamilyAPPLETA
    GssAddrFamilyBSC
    GssAddrFamilyDSS
    GssAddrFamilyOSI
    GssAddrFamilyNETBIOS
    GssAddrFamilyX25
)

GSSAPI Extensions

The Go bindings define the GssapiExtension type to represent non-standard GSSAPI extensions:

type GssapiExtension int

const (
    GssapiExtHasChannelBound         GssapiExtension = iota
    GssapiExtHasInquireSecContextByOid
    GssapiExtInquireName
    GssapiExtHasGetNameAttributes
    GssapiExtHasSetNameAttributes
    GssapiExtHasDeleteNameAttributes
    GssapiExtHasExportNameComposite
    GssapiExtHasIndicateMechsByAttrs
    GssapiExtHasInquireAttrsForMech
    GssapiExtHasDisplayMechAttr
)

Object Identifier Sets

In the Go bindings, OID sets are represented as slices of Oid types ([]Oid).

Provider

The Provider interface is a key component that acts as a factory for GSSAPI primitives, including names, credentials, and security contexts. This interface includes implementations of the routines defined in RFC 2743 §§ 2.1.1, 2.2.1, 2.2.2, 2.2.9, 2.4.2 and 2.4.5:

type Provider interface {
	ImportName(name string, nameType GssNameType) (GssName, error)
	AcquireCredential(name GssName, mechs []GssMech, usage CredUsage, lifetime time.Duration) (Credential, error)
	InitSecContext(name GssName, opts ...InitSecContextOption) (SecContext, error)
	AcceptSecContext(cred Credential, cb *ChannelBinding) (SecContext, error)
	ImportSecContext(b []byte) (SecContext, error)
 	InquireNamesForMech(m GssMech) ([]GssNameType, error)
  IndicateMechs() ([]GssMech, error)
	HasExtension(e GssapiExtension) bool
}

In the Go bindings, GSSAPI primitives are represented by the GssName, Credential, and SecContext interfaces, which are documented below.

The interface is further documented below.

Names

The Go bindings define the GssName interface to represent GSSAPI names (types INTERNAL NAME and MN) as described in RFC 2743 § 4. This interface includes support for the following name-related calls: GSS_Compare_name, GSS_Display_name, GSS_Import_name, GSS_Release_name, GSS_Inquire_mechs_for_name, GSS_Canonicalize_name, GSS_Export_name, and GSS_Duplicate_name.

type GssNameType int

type GssName interface {
	Compare(other GssName) (bool, error)
	Display() (string, GssNameType, error)
	Release() error
	InquireMechs() ([]GssMech, error)
	Canonicalize(GssMech) (GssName, error)
	Export() ([]byte, error)
	Duplicate() (GssName, error)
}

For more details on the types and interfaces related to names, see the sections on Names and Name Types.

Mechanisms

GSSAPI mechanisms are identified by unique object identifiers (OIDs). The Go bindings define the GssMech interface:

type GssMech interface {
	Oid() Oid
	OidString() string
	String() string
}

The gssMechImp implementation is provided as a convenience for provider implementations and clients of the interface. It supports the known mechanisms GSS_MECH_KRB5, GSS_MECH_IAKERB, and GSS_MECH_SPNEGO.

An implementation may need to obtain a GssMech from an OID. The standard implementation offers the following function for use with gssMechImpl:

func MechFromOid(oid Oid) (gssMechImpl, error)

If a provider needs to support a different mechanism, it can be added to gssMechImpl via a pull request to the go-gssapi repository. Alternatively, a new implementation of GssMech can be created for use by that GSSAPI implementation. Depending on the requirements, a replacement for MechFromOid may also need to be provided for the new mechanism.

Credentials

The Go bindings define the Credential interface, representing the CREDENTIAL HANDLE type from RFC 2743. This interface encompasses credential management functions as defined in RFC 2743 § 2.1, and is further documented in the Credentials section.

type Credential interface {
	Release() error
	Inquire() (*CredInfo, error)
	Add(name GssName, mech GssMech, usage CredUsage, initiatorLifetime time.Duration, acceptorLifetime time.Duration) error
	InquireByMech(mech GssMech) (*CredInfo, error)
}

The Provider method AcquireCredential reflects the credential constructor functionality described in RFC 2743 § 2.1.1.

Security contexts

The Go bindings represent security contexts using the SecContext interface rather than a context ID. The methods on the interface correspond to the context-level routines defined in RFC 2743 § 2.2:

type SecContext interface {
        Delete() ([]byte, error)
        ProcessToken([]byte) error
        ExpiresAt() (*GssLifetime, error)
        Inquire() (*SecContextInfo, error)
        WrapSizeLimit(bool, uint, QoP) (uint, error)
        Export() ([]byte, error)
        GetMIC([]byte, QoP) ([]byte, error)
        VerifyMIC([]byte, []byte) (QoP, error)
        Wrap([]byte, bool, QoP) ([]byte, bool, error)
        Unwrap([]byte) ([]byte, bool, QoP, error)

        ContinueNeeded() bool
        Continue([]byte) ([]byte, error)
}

The Inquire method returns a structure as defined below:

type SecContextInfo struct {
    InitiatorName    GssName
    AcceptorName     GssName
    Mech             GssMech
    Flags            ContextFlag
    ExpiresAt        GssLifetime
    LocallyInitiated bool
    FullyEstablished bool
    ProtectionReady  bool
    Transferrable    bool
}

Security contexts are constructed using the Provider methods InitSecContext, AcceptSecContext and ImportSecContext.

Status Values

RFC 2743 § 1.2.1 specifies two status code return values (major and minor) for each GSSAPI call. The major value is used to convey fatal errors and informational codes, while the minor code can be used to convey mechanism-specific errors, with values left to the implementation.

The Go bindings use Go's standard error interface instead. Two types are specified: InfoStatus and FatalStatus, both implementing the error interface.

  • InfoStatus objects are returned when an informational code is available but a function otherwise succeeded. This is only the case for the message-related methods of SecContext, such as SecContext.VerifyMIC and SecContext.Unwrap.
  • FatalStatus objects are returned when a function fails. Fatal errors may also include an embedded InfoStatus error.

After calls to the message-related methods of SecContext, callers can use the Go errors package to determine whether a response is fatal or not:

err := gssapi.SomeFunction()
info := gssapi.InfoStatus{}
if errors.As(err, &info) {
    log.Printf("Warning: %s", info) // e.g., an out-of-order message
} else {
    panic(err)
}

Outside the scope of message-related methods, all error responses are considered fatal.

The InfoStatus and FatalStatus types implement the Unwrap() method as defined in the standard error package:

type InfoStatus struct {
    InformationCode InformationCode
    MechErrors      []error
}

type FatalStatus struct {
    InfoStatus
    FatalErrorCode FatalErrorCode
}

func (e InfoStatus) Unwrap() []error {
    // Returns informational error objects
}

func (e FatalStatus) Unwrap() []error {
    // Returns both fatal and informational error objects
}
  • The Unwrap() method of InfoStatus returns a list of informational error objects.
  • The Unwrap() method of FatalStatus returns a list of error and informational objects.

The Go GSSAPI spec defines the following variables, correlating to the fatal and informational codes defined by RFC 2743. These variables implement the error interface:

Variable RFC 2743 Value
ErrBadBindings GSS_S_BAD_BINDINGS
ErrBadMech GSS_S_BAD_MECH
ErrBadName GSS_S_BAD_NAME
ErrBadNameType GSS_S_BAD_NAMETYPE
ErrBadStatus GSS_S_BAD_STATUS
ErrBadMic GSS_S_BAD_SIG
ErrBadSig = ErrBadMic GSS_S_BAD_MIC = GSS_S_BAD_SIG
ErrContextExpired GSS_S_CONTEXT_EXPIRED
ErrCredentialsExpired GSS_S_CREDENTIALS_EXPIRED
ErrDefectiveCredential GSS_S_DEFECTIVE_CREDENTIAL
ErrDefectiveToken GSS_S_DEFECTIVE_TOKEN
ErrFailure GSS_S_FAILURE
ErrNoContext GSS_S_NO_CONTEXT
ErrNoCred GSS_S_NO_CRED
ErrBadQop GSS_S_BAD_QOP
ErrUnauthorized GSS_S_UNAUTHORIZED
ErrUnavailable GSS_S_UNAVAILABLE
ErrDuplicateElement GSS_S_DUPLICATE_ELEMENT
ErrNameNotMn GSS_S_NAME_NOT_MN
InfoContinueNeeded GSS_S_CONTINUE_NEEDED
InfoDuplicateToken GSS_S_DUPLICATE_TOKEN
InfoOldToken GSS_S_OLD_TOKEN
InfoUnseqToken GSS_S_UNSEQ_TOKEN
InfoGapToken GSS_S_GAP_TOKEN

These values are returned by InfoStatus.Unwrap() and FatalStatus.Unwrap().

These error variables can be used by callers to inspect the error stack, for example:

err := gssapi.SomeFunction()
if err != nil {
    if errors.Is(err, gssapi.ErrContextExpired) {
        doLogin()
    } else {
        return err
    }
}

The Go standard library's errors.Is() function uses the Unwrap() method on the InfoStatus and FatalStatus types to provide this functionality.

Informational codes are only returned from a small number of methods (SecContext.VerifyMIC() and SecContext.Unwrap()). Therefore, except in these cases, a non-nil error return value can be considered fatal.

A nil status value represents GSS_S_COMPLETE —i.e., success.

GSSAPI primitives

Names

GSSAPI defines name types which are represented by unique object identifiers (OIDs). Names of a specified type are represented by an octet string. The Go bindings define the GssName interface, which represents the INTERNAL NAME and MN types as described in RFC 2743. Name objects correspond to a particular name type and may optionally be associated with a particular GSSAPI mechanism (referred to as an MN or mechanism name).

Name Types

The Go bindings define the GssNameType concrete type and a set of constants of that type corresponding to the name types defined in RFC 2743 § 4:

Go Bindings Constants RFC 2743 Reference
GSS_NT_HOSTBASED_SERVICE § 4.1: Host-Based Service Name Form
GSS_NT_USER_NAME § 4.2: User Name Form
GSS_NT_MACHINE_UID_NAME § 4.3: Machine UID Form
GSS_NT_STRING_UID_NAME § 4.4: String UID Form
GSS_NT_ANONYMOUS § 4.5: Anonymous Nametype
GSS_NO_OID § 4.6: GSS_C_NO_OID
GSS_NT_EXPORT_NAME § 4.7: Exported Name Object
GSS_NO_NAME § 4.8: GSS_C_NO_NAME
GSS_NT_COMPOSITE_EXPORT RFC 6680 § 8: Composite Export Name

Additionally, the following Kerberos-specific name type constants are defined:

  • GSS_KRB5_NT_PRINCIPAL_NAME (from RFC 1964 § 2.1.1)
  • GSS_KRB5_NT_ENTERPRISE_NAME (from RFC 8606 § 5)
  • GSS_KRB5_NT_X509_CERT (for S4U2Self, MIT Kerberos 1.19)

And SPKM-specific name types:

  • GSS_SPKM_NT_USER_NAME
  • GSS_SPKM_NT_MACHINE_UID_NAME
  • GSS_SPKM_NT_STRING_UID_NAME

The GssNameType type implements the following methods:

type GssNameType int

// Oid returns the object identifier corresponding to the name type.
func (nt GssNameType) Oid() Oid {
    // Implementation details
}

// OidString returns a printable version of the object identifier associated with the name type.
func (nt GssNameType) OidString() string {
    // Implementation details
}

// String returns a printable version of the name type, e.g., "GSS_NT_ANONYMOUS".
func (nt GssNameType) String() string {
    // Implementation details
}

The following function is provided to map a name OID to a name type:

// NameFromOid returns the name type associated with an OID, or an error if the OID is unknown.
func NameFromOid(oid Oid) (GssNameType, error) {
    // Implementation details
}

GssName Interface

RFC 2743 defines a number of calls related to names. The Go bindings, however, define an interface. Providers must implement the following GssName interface:

type GssName interface {
	Compare(other GssName) (bool, error)       // RFC 2743 § 2.4.3
	Display() (string, GssNameType, error)     // RFC 2743 § 2.4.4
	Release() error                            // RFC 2743 § 2.4.6
	InquireMechs() ([]GssMech, error)          // RFC 2743 § 2.4.13
	Canonicalize(GssMech) (GssName, error)     // RFC 2743 § 2.4.14
	Export() ([]byte, error)                   // RFC 2743 § 2.4.15
	Duplicate() (GssName, error)               // RFC 2743 § 2.4.16
}

Compare(other GssName) (equal bool, err error)

This method implements GSS_Compare_Name from RFC 2743 § 2.4.3.

  • Inputs:

    • other: the second name for comparison
  • Outputs:

    • equal: boolean value indicating whether the two names are equal
    • err: error if one occurred, otherwise nil

Display() (disp string, nt GssNameType, err error)

This method implements GSS_Display_Name from RFC 2743 § 2.4.4.

  • Outputs:
    • disp: string representation of the name
    • nt: type of the name
    • err: error if one occurred, otherwise nil

Release() (err error)

This method implements GSS_Release_Name from RFC 2743 § 2.4.6.

  • Outputs:
    • err: error if one occurred, otherwise nil

InquireMechs() (mechs []GssMech, err error)

This method implements GSS_Inquire_mechs_for_name from RFC 2743 § 2.4.13.

  • Outputs:
    • mechs: set of mechanisms that support the name
    • err: error if one occurred, otherwise nil

Canonicalize(mech GssMech) (name GssName, err error)

This method implements GSS_Canonicalize_name from RFC 2743 § 2.4.14.

  • Inputs:

    • mech: the explicit mechanism to be used to canonicalize the name
  • Outputs:

    • name: the canonical GssName. This must be released using GssName.Release()
    • err: error if one occurred, otherwise nil
  • Example:

    name1, err := lib.ImportName("foo", gssapi.GSS_NT_USER_NAME)
    if err != nil {
        panic(err)
    }
    defer name1.Release()
    
    canon, err := name1.Canonicalize(gssapi.GSS_MECH_KRB5)
    if err != nil {
        panic(err)
    }
    defer canon.Release()

Export() (exp []byte, err error)

This method creates an exported byte representation of a mechanism name (MN) that is the result of a call to CanonicalizeName() or Provider.AcceptSecContext(). It corresponds to the GSS_Export_name call defined in RFC 2743 § 2.4.15.

  • Outputs:
    • exp: the exported name representation
    • err: error if one occurred, otherwise nil

The exported name can be imported using Provider.ImportName() with the GSS_NT_EXPORT_NAME name type, even after the original name has been released.

Duplicate() (name GssName, err error)

This method implements GSS_Duplicate_name from RFC 2743 § 2.4.16.

  • Outputs:
    • name: the duplicated name. This must be released using GssName.Release()
    • err: error if one occurred, otherwise nil

The output name remains valid even if the source name is released.

Instantiating names

The Provider method ImportName can be used to construct a Gssname for use with the AcquireCredential or InitSecContext Provider methods and the Add Credential method - see Provider and Credential for more information.

Credentials

RFC 2743 § 2.1 defines a set of credential-related calls. In the Go bindings, credentials are represented as an interface:

type Credential interface {
	Release() error                                         // RFC 2743 § 2.1.2
	Inquire() (*CredInfo, error)                            // RFC 2743 § 2.1.3
	Add(name GssName, mech GssMech, usage CredUsage, initiatorLifetime time.Duration, acceptorLifetime time.Duration) error // RFC 2743 § 2.1.4
	InquireByMech(mech GssMech) (*CredInfo, error)          // RFC 2743 § 2.1.5
}

Supporting Types

type CredUsage int

// Credential usage values as defined in RFC 2743 § 2.1.1
const (
	CredUsageInitiateAndAccept CredUsage = iota
	CredUsageInitiateOnly
	CredUsageAcceptOnly
)

// Returned by InquireByMech
type CredInfo struct {
	Name            string
	NameType        GssNameType
	InitiatorExpiry *time.Time
	AcceptorExpiry  *time.Time
	Usage           CredUsage
	Mechs           []GssMech
}

Credential Interface

Release() (err error)

Releases the credential when it is no longer required. This method corresponds to GSS_Release_cred from RFC 2743 § 2.1.2.

  • Output:
    • err: error if one occurred, otherwise nil

Inquire() (info *CredInfo, err error)

Returns information about the credential, implementing the GSS_Inquire_cred call from RFC 2743 § 2.1.3.

  • Output:
    • info: information about the credential
    • err: error if one occurred, otherwise nil

The InitiatorExpiry and AcceptorExpiry fields of info are only populated if the credential contains initiator and acceptor credential elements, respectively. A nil value represents unsupported or indefinite lifetime, and the zero time value represents an expired credential. For multi-mechanism credentials, the lifetimes represent the shortest lifetime of the elements in the credential.

The Usage field represents the types of credentials (accept, initiator, or both) held.

Use InquireByMech() for more fine-grained, mechanism-specific information.

Add(name GssName, mech GssMech, usage CredUsage, initiatorLifetime time.Duration, acceptorLifetime time.Duration) (err error)

Adds a credential element to the Credential. A credential may hold elements for one or more mechanisms, for use by either an acceptor or initiator. It may not hold multiple acceptor or initiator elements for the same mechanism. This method implements the GSS_Add_cred call described in RFC 2743 § 2.1.4.

The RFC describes a mode where a new credential handle can be returned instead of modifying the existing handle. The Go bindings define the addition of credentials to the existing Credential only.

The RFC details a set of outputs related to the added credential. These are not returned by the Go bindings; callers should use Inquire() or InquireByMech() instead.

  • Inputs:

    • name: the name to add, or nil to add a credential that will trigger a request for a default name by InitSecContext
    • mech: the mechanism to add
    • usage: the desired credential usage
    • initiatorLifetime: the desired lifetime of the initiator credential if usage is CredUsageInitiateOnly or CredUsageInitiateAndAccept, or the zero value for a default value
    • acceptorLifetime: the desired lifetime of the acceptor credential if usage is CredUsageAcceptOnly or CredUsageInitiateAndAccept, or the zero value for a default value
  • Output:

    • err: error if one occurred, otherwise nil

InquireByMech(mech GssMech) (info *CredInfo, err error)

Returns information about the credential element related to mech, implementing the GSS_Inquire_cred_by_mech call from RFC 2743 § 2.1.5. This call is a finer-grained, mechanism-specific version of Inquire.

  • Output:
    • info: information about the credential element
    • err: error if one occurred, otherwise nil

The InitiatorExpiry and AcceptorExpiry fields are only populated if the credential element may be used by an initiator or acceptor, respectively. A nil value represents unsupported or indefinite lifetime, and the zero time value represents an expired credential.

The Usage field represents the types of credential elements (accept, initiator, or both) held for the mech.

Instantiating Credentials

The Provider method AcquireCredential can be used to construct a Credential for use with the InitSecContext or AcceptSecContext methods. See the Provider section for more information.

Security Contexts

A security context is created through the (possible mutual) authentication of an initiator to an acceptor. Authentication is achieved by exchanging tokens between the parties until both agree that the process is complete. RFC 2743 § 2.2 defines a set of calls related to security contexts. The Go bindings define an interface for operations on existing contexts, and the Provider interface provides methods to construct new contexts.

type SecContext interface {
    Delete() ([]byte, error)                 // RFC 2743 § 2.2.3
    ProcessToken([]byte) error               // RFC 2743 § 2.2.4
    ExpiresAt() (*time.Time, error)          // RFC 2743 § 2.2.5
    Inquire() (*SecContextInfo, error)       // RFC 2743 § 2.2.6
    WrapSizeLimit(bool, uint) (uint, error)  // RFC 2743 § 2.2.7
    Export() ([]byte, error)                 // RFC 2743 § 2.2.8
    GetMIC([]byte) ([]byte, error)           // RFC 2743 § 2.3.1
    VerifyMIC([]byte, []byte) error          // RFC 2743 § 2.3.2
    Wrap([]byte, bool) ([]byte, bool, error) // RFC 2743 § 2.3.3
    Unwrap([]byte) ([]byte, bool, error)     // RFC 2743 § 2.3.4

    ContinueNeeded() bool
    Continue([]byte) ([]byte, error)
}

type SecContextInfo struct {
    InitiatorName    GssName
    AcceptorName     GssName
    Mech             GssMech
    Flags            ContextFlag
    ExpiresAt        GssLifetime
    LocallyInitiated bool
    FullyEstablished bool
    ProtectionReady  bool
    Transferrable    bool
}

type GssLifetime struct {
	Status    GssLifetimeStatus
	ExpiresAt time.Time
}

type GssLifetimeStatus int

const (
	GssLifetimeAvailable  GssLifetimeStatus = iota
	GssLifetimeExpired
	GssLifetimeIndefinite
)

SecContext Interface

Delete() (token []byte, err error)

Delete() clears context-specific information. It should be called on any non-nil SecContext object to release associated resources. If a token is returned, it should be sent to the peer to notify them to clear their own context. This call implements GSS_Delete_sec_context from RFC 2743 § 2.2.3.

  • Output:
    • token: Token to send to the peer, if not empty
    • err: Error if one occurred, otherwise nil

ProcessToken(token []byte) (err error)

ProcessToken implements GSS_Process_context_token from RFC 2743 § 2.2.4. It processes context tokens received from a peer after the context is fully established. One use is for processing the output of Delete() from the peer.

  • Inputs:

  • token: Context token received from the peer

  • Output:

  • err: Error if one occurred, otherwise nil

ExpiresAt() (lifetime *GssLifetime, err error)

ExpiresAt returns the lifetime information for the security context, implementing GSS_Context_time from RFC 2743 § 2.2.5.

  • Output:
  • lifetime: Lifetime information including status and expiry time, or nil if context expiry is not supported
  • err: Error if one occurred, otherwise nil

It is not an error for context expiry to be unsupported by the provider or mechanism; in this case, both lifetime and err will be nil.

Inquire() (info *SecContextInfo, err error)

Inquire returns information about the security context, implementing GSS_Inquire_context from RFC 2743 § 2.2.6.

  • Output:
  • info: Information about the security context
  • err: Error if one occurred, otherwise nil

The InitiatorName and AcceptorName fields represent MN (mechanism) names. The value of Flags may change during the authentication process as more protection is added to the context.

ExpiresAt is a structure with members indicating whether the context has expired or whether it has indefinite validity, otherwise the time at which it expires. This replaces the integer value specified in RFC 2743 and 2744, that uses magic values to represent expired and indefinite states; these are not suitable for use with the Go time types.

LocallyInitiated is true if the caller initiated the security context. FullyEstablished is true once the context is fully established; otherwise, it is in the CONTINUE_NEEDED state.

ProtectionReady indicates when per-message methods can be used to protect messages, constrained to the values of ContextFlagDeleg, ContextFlagMutual, ContextFlagReplay, ContextFlagSequence, ContextFlagConf, and ContextFlagInteg in the Flags field. If the context is not yet fully established, these flag values may change as additional facilities are confirmed.

WrapSizeLimit(conf bool, outSizeMax uint, qop QoP) (inSizeMax uint, err error)

This method returns the maximum unwrapped message size that, when wrapped, takes no more than outSizeMax bytes. It implements GSS_Wrap_size_limit from RFC 2743 § 2.2.7.

  • Inputs:

  • conf: Whether the wrapped message would include confidentiality

  • outSizeMax: Maximum allowed wrapped message size

  • qop: Quality of protection requested, zero for default (see RFC 2743 § 1.2.4 for details)

  • Output:

  • inSizeMax: Maximum unwrapped message size

  • err: Error if one occurred, otherwise nil

Export() (tok []byte, err error)

Export() generates an inter-process token transferable to another process within the system, implementing GSS_Export_sec_context from RFC 2743 § 2.2.8. The receiving process should call Provider.ImportSecContext() to accept the transfer. Upon success, the original security context is deactivated and no longer available for use.

  • Output:
  • tok: Opaque inter-process token
  • err: Error if one occurred, otherwise nil

GetMIC(msg []byte, qop QoP) (tok []byte, err error)

Corresponding to GSS_GetMIC from RFC 2743 § 2.3.1, this method generates an integrity check token over the supplied message.

  • Inputs:

  • msg: Message to generate integrity token for

  • qop: Quality of protection requested, zero for default (see RFC 2743 § 1.2.4 for details)

  • Output:

  • tok: Integrity token

  • err: Error if one occurred, otherwise nil

Detached integrity tokens generated by this method and verified by VerifyMIC can be used with protocols that cannot accept wrapped messages, by transferring the message and integrity information separately between peers.

VerifyMIC(msg, tok []byte) (qop QoP, err error)

VerifyMIC verifies a message against an integrity token generated by GetMIC(), corresponding to GSS_VerifyMIC from RFC 2743 § 2.3.2. Message replay and sequencing features are used if supported by the underlying security context.

  • Inputs:

  • msg: Message over which to validate the integrity

  • tok: Integrity token generated by the peer using GetMIC

  • Output:

  • err: Error if one occurred, otherwise nil

  • qop: Quality of protection provided, zero for default (see RFC 2743 § 1.2.4 for details)

Wrap(msgIn []byte, confReq bool, qop QoP) (msgOut []byte, confState bool, err error)

This method generates a new message that incorporates the input message and relevant protections as a single set of bytes, implementing GSS_Wrap from RFC 2743 § 2.3.3.

  • Inputs:

  • msgIn: Input (unwrapped) message

  • confReq: Whether confidentiality is required

  • qop: Quality of protection requested, zero for default (see RFC 2743 § 1.2.4 for details)

  • Output:

  • msgOut: Wrapped message

  • confState: Whether confidentiality was applied to msgOut

  • err: Error if one occurred, otherwise nil

The wrapped message will be encrypted if confidentiality was requested and supported.

Unwrap(msgIn []byte) (msgOut []byte, confState bool, qop QoP, err error)

Unwrap takes a message generated by the peer's call to Wrap(), validates its protections, and optionally decrypts its contents depending on whether confidentiality was applied in the Wrap() call.

  • Inputs:

  • msgIn: Input (wrapped) message from peer

  • Output:

  • msgOut: Unwrapped message

  • confState: Whether the wrapped message was confidential (encrypted)

  • qop: Quality of protection provided, zero for default (see RFC 2743 § 1.2.4 for details)

  • err: Error if one occurred, otherwise nil

ContinueNeeded() (c bool)

ContinueNeeded indicates whether more context-initialization tokens need to be exchanged with the peer to complete the security context. This call is equivalent to checking for the GSS_S_CONTINUE_NEEDED status from GSS_Init_sec_context or GSS_Accept_sec_context.

  • Output:
  • c: Whether more message exchanges are required

Continue(tokIn []byte) (tokOut []byte, err error)

The Continue method is used by initiators and acceptors during the context-initialization loop to process a token from the peer. It is equivalent to calling GSS_Init_sec_context or GSS_Accept_sec_context on a partially open context.

  • Inputs:

  • tokIn: Context initialization token received from the peer

  • Output:

  • tokOut: New token to send to the peer; zero length if no token should be sent

  • err: Error if one occurred, otherwise nil

The caller should check the result of ContinueNeeded to determine whether the initialization loop has completed.

Provider

As outlined in Provider registration interface, the Go GSSAPI bindings support multiple pluggable GSSAPI providers.

Each provider implements the Provider interface, which developers use to write GSSAPI client and server code:

type Provider interface {
    ImportName(name string, nameType GssNameType) (GssName, error)                                                // RFC 2743 § 2.4.5
    AcquireCredential(name GssName, mechs []GssMech, usage CredUsage, lifetime time.Duration) (Credential, error) // RFC 2743 § 2.1.1
    InitSecContext(name GssName, opts ...InitSecContextOption) (SecContext, error)                                // RFC 2743 § 2.2.1
    AcceptSecContext(cred Credential, cb *ChannelBinding) (SecContext, error)                                     // RFC 2743 § 2.2.2
    ImportSecContext(b []byte) (SecContext, error)                                                                // RFC 2743 § 2.2.9
    InquireNamesForMech(m GssMech) ([]GssNameType, error)                                                         // RFC 2743 § 2.4.12
    HasExtension(e GssapiExtension) bool
}

ImportName(name string, nameType GssNameType) (gn GssName, err error)

The ImportName provider method converts a GSS name (represented as a string) and its namespace (name type) to an internal representation usable with other GSSAPI calls. This method corresponds to GSS_Import_name from RFC 2743 § 2.4.5.

  • Inputs:

  • name: String representation of the name, syntax depends on nameType

  • nameType: Type or syntax of name, or nil to use a mechanism-specific default printable syntax

  • Output:

  • gn: GSSAPI internal name - This MUST be released using GssName.Release()

  • err: Error if one occurred, otherwise nil

AcquireCredential(name GssName, mechs []GssMech, usage CredUsage, lifetime time.Duration) (cred Credential, err error)

The AcquireCredential provider method acquires credentials for use with a security context initiator or acceptor, corresponding to GSS_Acquire_cred from RFC 2743 § 2.1.1.

  • Inputs:

  • name: Desired name, or nil to use a default

  • mechs: Set of mechanisms to try acquiring credentials for, or nil for the default

  • usage: Intended usage for the credentials: CredUsageInitiateOnly, CredUsageAcceptOnly, or CredUsageInitiateAndAccept

  • lifetime: Desired lifetime of the credentials, or zero for the maximum permitted lifetime

  • Output:

  • cred: Credential object containing the acquired credential elements

  • err: Error if one occurred, otherwise nil

InitSecContext(name GssName, opts ...InitSecContextOption) (ctx SecContext, err error)

Security context initiators use InitSecContext to begin the process of context establishment with a peer, corresponding to GSS_Init_sec_context from RFC 2743 § 2.2.1. This method is intended to be called only once to begin the establishment process. If more steps are required, the Continue method on the returned SecContext object should be used.

  • Inputs:

  • name: Name of the target acceptor (peer)

  • opts: Establishment options

  • Output:

  • ctx: Security context - This MUST be released using SecContext.Delete()

  • err: Error if one occurred, otherwise nil

The caller should use ContinueNeeded on the returned context to determine whether more token exchanges with the peer are required to fully establish the context. Note that some mechanisms support using protection services before a context is fully established. Check the ProtectionReady flag after calling Inquire on the returned context to determine if this is the case.

Note that this method does not return the actual mechanism, available protection services, or lifetime; callers can query that information using the Inquire method on the returned context.

AcceptSecContext(cred Credential, cb *ChannelBinding) (ctx SecContext, err error)

Acceptors use AcceptSecContext upon receiving a context initialization token from the peer, corresponding to GSS_Accept_sec_context from RFC 2743 § 2.2.2.

  • Inputs:

  • cred: Acceptor credential, or nil to use the default

  • cb: Channel binding information, or nil for no channel bindings

  • Output:

  • ctx: Security context - This MUST be released using SecContext.Delete()

  • err: Error if one occurred, otherwise nil

The caller should check the return value of ContinueNeeded and use Inquire on the returned context if required.

ImportSecContext(b []byte) (ctx SecContext, err error)

Imports an inter-process token generated by a prior call to Export. The method corresponds to the GSS_Import_sec_context call from RFC 2743 § 2.2.9.

  • Inputs:

  • b: Inter-process token bytes

  • Output:

  • ctx: Security context - This MUST be released using SecContext.Release()

  • err: Error if one occurred, otherwise nil

InquireNamesForMech(m GssMech) (nt []GssNameType, err error)

Returns a list of name types supported by the mechanism m. The method implements GSS_Inquire_names_for_mech from RFC 2743 § 2.4.12.

  • Inputs:

    • m: Mechanism to query
  • Output:

    • nt: List of name types supported by the mechanism
    • err: Error if one occurred, otherwise nil

IndicateMechs() (mechs []GssMech, err error)

Returns a list of mechanisms supported by the provider. The method implements GSS_Indicate_mechs from RFC 2743 § 2.4.2.

  • Output:
    • mechs: List of supported mechanisms
    • err: Error if one occured, otherwise nil

HasExtension(e GssapiExtension) bool

Reports whether a non-standard extension to GSSAPI is available. This method allows providers to advertise support for extensions beyond the standard GSSAPI specification.

  • Inputs:

    • e: The extension to check for
  • Output:

    • bool: True if the extension is supported, false otherwise

Context Initialization Options

The following option functions are provided for generating optional parameters to the InitSecContext method:

WithInitiatorCredential(cred Credential) InitSecContextOption

Supports the use of a source credential when initiating a security context, corresponding to the claimant_cred_handle parameter to GSS_Init_sec_context from the RFC.

WithInitiatorMech(mech GssMech) InitSecContextOption

Supports the use of a specific mechanism when establishing the context, corresponding to the mech_type parameter to GSS_Init_sec_context from the RFC.

WithInitiatorFlags(flags ContextFlag) InitSecContextOption

Allows the caller to control the requested protection flags when establishing a security context, corresponding to the *_req_flag parameters of GSS_Init_sec_context from the RFC.

WithInitiatorLifetime(life time.Duration) InitSecContextOption

Supports the use of a non-default context lifetime, corresponding to the lifetime_req parameter of GSS_Init_sec_context from the RFC.

WithChannelBinding(cb *ChannelBinding) InitSecContextOption

Supports the use of channel binding information when establishing the context, corresponding to the input_chan_bindings parameter of GSS_Init_sec_context from the RFC.

Clone this wiki locally