// Copyright (c) 2026 Petr BalvĂ­n (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" )