keytab
import "github.com/TheManticoreProject/Manticore/network/kerberos/v5/credcache/keytab"
Package keytab reads and writes the MIT/Heimdal Kerberos keytab file (the “.keytab” / krb5.keytab format) in versioned format 2 (magic 0x05 0x02), the interchange format Unix Kerberos tooling (ktutil, kinit -kt, klist -k) uses to store a principal’s long-term keys on disk.
A keytab holds one or more entries, each binding a principal to a single long-term key (an enctype plus the raw key bytes) and a key version number (kvno). Unlike a credential cache (see the ccache package) it stores permanent keys, not tickets, so it lets a client authenticate non-interactively — the keytab-based analogue of pass-the-key.
Wire format (documented at https://web.mit.edu/kerberos/krb5-devel/doc/formats/keytab_file_format.html):
keytab {
uint16 file_format_version = 0x0502
keytab_entry entries[*] (runs to EOF)
}
keytab_entry {
int32 size // bytes that FOLLOW this field;
// negative = a hole (deleted entry),
// its magnitude is the hole length
uint16 num_components // v2 does NOT count the realm
counted_octet_string realm
counted_octet_string components[num_components]
uint32 name_type // v2 only
uint32 timestamp // Unix seconds
uint8 vno8 // 8-bit key version number
keyblock key
uint32 vno // OPTIONAL: present when >= 4 bytes
// remain in size and it is non-zero;
// supersedes vno8
}
keyblock { uint16 enctype; counted_octet_string key }
counted_octet_string { uint16 length; uint8 data[length] }
Version 2 is big-endian throughout (version 1 used host byte order and folded the realm into num_components; only version 2 is emitted today and is what this package writes). This package implements the wire format and entry selection; wiring a selected key into a live client is done by the kerberos client layer.
Index
- Constants
- type Entry
- type Keytab
- func Load(path string) (*Keytab, error)
- func New() *Keytab
- func Unmarshal(data []byte) (*Keytab, error)
- func (kt *Keytab) Add(principal Principal, etype int, key []byte, kvno uint32)
- func (kt *Keytab) Find(principal string, etype int, kvno int) []*Entry
- func (kt *Keytab) Marshal() ([]byte, error)
- func (kt *Keytab) Save(path string) error
- func (kt *Keytab) Select(principal string, etype int, kvno int) *Entry
- type Principal
Constants
Version2 is the file_format_version this package reads and writes: the first byte is always 0x05, the second is the version (2).
const Version2 = 0x0502
type Entry
Entry is a single keytab record: one long-term key for one principal.
type Entry struct {
Principal Principal
// Timestamp is when the entry was written, in Unix seconds (0 if unknown).
Timestamp uint32
// KVNO8 is the 8-bit key version number always present on the wire.
KVNO8 uint8
// KVNO is the optional 32-bit key version number. When non-zero it is written
// after the key and supersedes KVNO8 (kvnos above 255 need it). Zero means the
// 32-bit field is absent and KVNO8 is authoritative.
KVNO uint32
// EType is the key's encryption type (see iana.EType*).
EType uint16
// Key is the raw long-term key bytes.
Key []byte
}
func (Entry) Kvno
func (e Entry) Kvno() uint32
Kvno returns the effective key version number: the 32-bit KVNO when non-zero, otherwise the 8-bit KVNO8.
type Keytab
Keytab is a parsed keytab: an ordered list of key entries.
type Keytab struct {
Entries []Entry
}
func Load
func Load(path string) (*Keytab, error)
Load reads and parses a keytab file.
func New
func New() *Keytab
New returns an empty keytab.
func Unmarshal
func Unmarshal(data []byte) (*Keytab, error)
Unmarshal parses a keytab. Only versioned format 2 (0x0502) is supported.
func (*Keytab) Add
func (kt *Keytab) Add(principal Principal, etype int, key []byte, kvno uint32)
Add appends an entry binding a key to a principal. The 8-bit KVNO8 is set from kvno (its low byte) and, when kvno exceeds 255, the 32-bit KVNO too. NameType defaults to NT-PRINCIPAL when zero. The key bytes are copied.
func (*Keytab) Find
func (kt *Keytab) Find(principal string, etype int, kvno int) []*Entry
Find returns pointers to every entry matching the filter, in file order. A principal of "" matches any principal; etype <= 0 matches any enctype; and kvno < 0 matches any key version.
func (*Keytab) Marshal
func (kt *Keytab) Marshal() ([]byte, error)
Marshal encodes the keytab in versioned format 2 (0x0502, big-endian).
func (*Keytab) Save
func (kt *Keytab) Save(path string) error
Save writes the keytab to path in versioned format 2, mode 0600.
func (*Keytab) Select
func (kt *Keytab) Select(principal string, etype int, kvno int) *Entry
Select returns the single best entry matching the filter, or nil when none match. “Best” is the highest key version number, breaking ties by enctype strength (AES256 > AES256-SHA2 > AES128 > AES128-SHA2 > RC4 > other). Pass principal "" for any principal, etype <= 0 for any enctype, and kvno < 0 to select the newest key rather than a specific version.
type Principal
Principal identifies the account a key belongs to: one or more name components, a realm, and the RFC 4120 name-type.
type Principal struct {
NameType uint32
Realm string
Components []string
}
func (Principal) String
func (p Principal) String() string
String renders the principal in the conventional “comp1/comp2@REALM” form.