Files
nfs/internal/rpc/gss.go
T

131 lines
3.4 KiB
Go
Raw Permalink Normal View History

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
// The RPCSEC_GSS credential of RFC 2203 as refined by RFC 5403: the
// credential body, the context establishment procedures and result, and
// the service levels none, integrity and privacy.
package rpc
import (
"sourcedock.dev/petrbalvin/nfs/internal/xdr"
)
// The RPCSEC_GSS authentication flavor.
const FlavorGSS = 6
// GSSVersion1 is the credential version of RFC 2203.
const GSSVersion1 = 1
// Credential procedures of the gss_proc union.
const (
GSSProcData = 0
GSSProcInit = 1
GSSProcContinue = 2
GSSProcDestroy = 3
)
// Service levels of rpc_gss_svc_t.
const (
SvcNone = 1
SvcIntegrity = 2
SvcPrivacy = 3
)
// A GSSCred is the decoded version one credential body: the version,
// the procedure, the sequence number, the service and the context
// handle, in the order RFC 2203 section 5.2.1 fixes for every
// procedure.
type GSSCred struct {
Version uint32
Proc uint32
Seq uint32
Service uint32
Handle []byte
}
// AppendGSSCred encodes the version one credential body. The context
// token of the control procedures travels in the procedure arguments,
// never in the credential.
func AppendGSSCred(b []byte, proc, seq, service uint32, handle []byte) []byte {
b = xdr.AppendUint32(b, GSSVersion1)
b = xdr.AppendUint32(b, proc)
b = xdr.AppendUint32(b, seq)
b = xdr.AppendUint32(b, service)
return xdr.AppendVarOpaque(b, handle)
}
// DecodeGSSCred decodes the version one credential body.
func DecodeGSSCred(body []byte) (GSSCred, error) {
d := xdr.NewDecoder(body)
var c GSSCred
var err error
if c.Version, err = d.Uint32(); err != nil {
return c, err
}
if c.Version != GSSVersion1 {
return c, ErrGSSCred
}
if c.Proc, err = d.Uint32(); err != nil {
return c, err
}
switch c.Proc {
case GSSProcData, GSSProcInit, GSSProcContinue, GSSProcDestroy:
default:
return c, ErrGSSCred
}
if c.Seq, err = d.Uint32(); err != nil {
return c, err
}
if c.Service, err = d.Uint32(); err != nil {
return c, err
}
c.Handle, err = d.VarOpaque()
return c, err
}
// ErrGSSCred marks a malformed version one credential: an unknown
// procedure or a version other than one.
var ErrGSSCred = &gssError{"malformed rpcsec gss version one credential"}
type gssError struct{ s string }
func (e *gssError) Error() string { return "rpc: " + e.s }
// AppendGSSInitRes encodes the RPCSEC_GSS_INIT result: the handle the
// server assigns, the major and minor status, the sequence window and
// the reply token.
func AppendGSSInitRes(b []byte, handle []byte, major, minor, window uint32, token []byte) []byte {
b = xdr.AppendVarOpaque(b, handle)
b = xdr.AppendUint32(b, major)
b = xdr.AppendUint32(b, minor)
b = xdr.AppendUint32(b, window)
return xdr.AppendVarOpaque(b, token)
}
// DecodeGSSInitRes decodes the RPCSEC_GSS_INIT result.
func DecodeGSSInitRes(payload []byte) (handle []byte, major, minor, window uint32, token []byte, err error) {
d := xdr.NewDecoder(payload)
if handle, err = d.VarOpaque(); err != nil {
return
}
if major, err = d.Uint32(); err != nil {
return
}
if minor, err = d.Uint32(); err != nil {
return
}
if window, err = d.Uint32(); err != nil {
return
}
token, err = d.VarOpaque()
return
}
// The AUTH_TLS authentication flavor of RFC 9289 and the STARTTLS
// token the server answers the probe with.
const (
FlavorTLS = 7
StarttlsToken = "STARTTLS"
)