keytab.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. // Package keytab implements Kerberos keytabs: https://web.mit.edu/kerberos/krb5-devel/doc/formats/keytab_file_format.html.
  2. package keytab
  3. import (
  4. "bytes"
  5. "encoding/binary"
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "os"
  11. "strings"
  12. "time"
  13. "unsafe"
  14. "github.com/jcmturner/gokrb5/v8/crypto"
  15. "github.com/jcmturner/gokrb5/v8/types"
  16. )
  17. const (
  18. keytabFirstByte byte = 05
  19. )
  20. // Keytab struct.
  21. type Keytab struct {
  22. version uint8
  23. Entries []entry
  24. }
  25. // Keytab entry struct.
  26. type entry struct {
  27. Principal principal
  28. Timestamp time.Time
  29. KVNO8 uint8
  30. Key types.EncryptionKey
  31. KVNO uint32
  32. }
  33. func (e entry) String() string {
  34. return fmt.Sprintf("% 4d %s %-56s %2d %-64x",
  35. e.KVNO8,
  36. e.Timestamp.Format("02/01/06 15:04:05"),
  37. e.Principal.String(),
  38. e.Key.KeyType,
  39. e.Key.KeyValue,
  40. )
  41. }
  42. // Keytab entry principal struct.
  43. type principal struct {
  44. NumComponents int16 `json:"-"`
  45. Realm string
  46. Components []string
  47. NameType int32
  48. }
  49. func (p principal) String() string {
  50. return fmt.Sprintf("%s@%s", strings.Join(p.Components, "/"), p.Realm)
  51. }
  52. // New creates new, empty Keytab type.
  53. func New() *Keytab {
  54. var e []entry
  55. return &Keytab{
  56. version: 2,
  57. Entries: e,
  58. }
  59. }
  60. // GetEncryptionKey returns the EncryptionKey from the Keytab for the newest entry with the required kvno, etype and matching principal.
  61. // If the kvno is zero then the latest kvno will be returned. The kvno is also returned for
  62. func (kt *Keytab) GetEncryptionKey(princName types.PrincipalName, realm string, kvno int, etype int32) (types.EncryptionKey, int, error) {
  63. var key types.EncryptionKey
  64. var t time.Time
  65. var kv int
  66. for _, k := range kt.Entries {
  67. if k.Principal.Realm == realm && len(k.Principal.Components) == len(princName.NameString) &&
  68. k.Key.KeyType == etype &&
  69. (k.KVNO == uint32(kvno) || kvno == 0) &&
  70. k.Timestamp.After(t) {
  71. p := true
  72. for i, n := range k.Principal.Components {
  73. if princName.NameString[i] != n {
  74. p = false
  75. break
  76. }
  77. }
  78. if p {
  79. key = k.Key
  80. kv = int(k.KVNO)
  81. t = k.Timestamp
  82. }
  83. }
  84. }
  85. if len(key.KeyValue) < 1 {
  86. return key, 0, fmt.Errorf("matching key not found in keytab. Looking for %q realm: %v kvno: %v etype: %v", princName.PrincipalNameString(), realm, kvno, etype)
  87. }
  88. return key, kv, nil
  89. }
  90. // Create a new Keytab entry.
  91. func newEntry() entry {
  92. var b []byte
  93. return entry{
  94. Principal: newPrincipal(),
  95. Timestamp: time.Time{},
  96. KVNO8: 0,
  97. Key: types.EncryptionKey{
  98. KeyType: 0,
  99. KeyValue: b,
  100. },
  101. KVNO: 0,
  102. }
  103. }
  104. func (kt Keytab) String() string {
  105. var s string
  106. s = `KVNO Timestamp Principal ET Key
  107. ---- ----------------- -------------------------------------------------------- -- ----------------------------------------------------------------
  108. `
  109. for _, entry := range kt.Entries {
  110. s += entry.String() + "\n"
  111. }
  112. return s
  113. }
  114. // AddEntry adds an entry to the keytab. The password should be provided in plain text and it will be converted using the defined enctype to be stored.
  115. func (kt *Keytab) AddEntry(principalName, realm, password string, ts time.Time, KVNO uint8, encType int32) error {
  116. // Generate a key from the password
  117. princ, _ := types.ParseSPNString(principalName)
  118. key, _, err := crypto.GetKeyFromPassword(password, princ, realm, encType, types.PADataSequence{})
  119. if err != nil {
  120. return err
  121. }
  122. // Populate the keytab entry principal
  123. ktep := newPrincipal()
  124. ktep.NumComponents = int16(len(princ.NameString))
  125. if kt.version == 1 {
  126. ktep.NumComponents += 1
  127. }
  128. ktep.Realm = realm
  129. ktep.Components = princ.NameString
  130. ktep.NameType = princ.NameType
  131. // Populate the keytab entry
  132. e := newEntry()
  133. e.Principal = ktep
  134. e.Timestamp = ts
  135. e.KVNO8 = KVNO
  136. e.KVNO = uint32(KVNO)
  137. e.Key = key
  138. kt.Entries = append(kt.Entries, e)
  139. return nil
  140. }
  141. // Create a new principal.
  142. func newPrincipal() principal {
  143. var c []string
  144. return principal{
  145. NumComponents: 0,
  146. Realm: "",
  147. Components: c,
  148. NameType: 0,
  149. }
  150. }
  151. // Load a Keytab file into a Keytab type.
  152. func Load(ktPath string) (*Keytab, error) {
  153. kt := new(Keytab)
  154. b, err := os.ReadFile(ktPath)
  155. if err != nil {
  156. return kt, err
  157. }
  158. err = kt.Unmarshal(b)
  159. return kt, err
  160. }
  161. // Marshal keytab into byte slice
  162. func (kt *Keytab) Marshal() ([]byte, error) {
  163. b := []byte{keytabFirstByte, kt.version}
  164. for _, e := range kt.Entries {
  165. eb, err := e.marshal(int(kt.version))
  166. if err != nil {
  167. return b, err
  168. }
  169. b = append(b, eb...)
  170. }
  171. return b, nil
  172. }
  173. // Write the keytab bytes to io.Writer.
  174. // Returns the number of bytes written
  175. func (kt *Keytab) Write(w io.Writer) (int, error) {
  176. b, err := kt.Marshal()
  177. if err != nil {
  178. return 0, fmt.Errorf("error marshaling keytab: %v", err)
  179. }
  180. return w.Write(b)
  181. }
  182. // Unmarshal byte slice of Keytab data into Keytab type.
  183. func (kt *Keytab) Unmarshal(b []byte) error {
  184. if len(b) < 2 {
  185. return fmt.Errorf("byte array is less than 2 bytes: %d", len(b))
  186. }
  187. //The first byte of the file always has the value 5
  188. if b[0] != keytabFirstByte {
  189. return errors.New("invalid keytab data. First byte does not equal 5")
  190. }
  191. //Get keytab version
  192. //The 2nd byte contains the version number (1 or 2)
  193. kt.version = b[1]
  194. if kt.version != 1 && kt.version != 2 {
  195. return errors.New("invalid keytab data. Keytab version is neither 1 nor 2")
  196. }
  197. //Version 1 of the file format uses native byte order for integer representations. Version 2 always uses big-endian byte order
  198. var endian binary.ByteOrder
  199. endian = binary.BigEndian
  200. if kt.version == 1 && isNativeEndianLittle() {
  201. endian = binary.LittleEndian
  202. }
  203. // n tracks position in the byte array
  204. n := 2
  205. l, err := readInt32(b, &n, &endian)
  206. if err != nil {
  207. return err
  208. }
  209. for l != 0 {
  210. if l < 0 {
  211. //Zero padded so skip over
  212. l = l * -1
  213. n = n + int(l)
  214. } else {
  215. if n < 0 {
  216. return fmt.Errorf("%d can't be less than zero", n)
  217. }
  218. if n+int(l) > len(b) {
  219. return fmt.Errorf("%s's length is less than %d", b, n+int(l))
  220. }
  221. eb := b[n : n+int(l)]
  222. n = n + int(l)
  223. ke := newEntry()
  224. // p keeps track as to where we are in the byte stream
  225. var p int
  226. var err error
  227. parsePrincipal(eb, &p, kt, &ke, &endian)
  228. ke.Timestamp, err = readTimestamp(eb, &p, &endian)
  229. if err != nil {
  230. return err
  231. }
  232. rei8, err := readInt8(eb, &p, &endian)
  233. if err != nil {
  234. return err
  235. }
  236. ke.KVNO8 = uint8(rei8)
  237. rei16, err := readInt16(eb, &p, &endian)
  238. if err != nil {
  239. return err
  240. }
  241. ke.Key.KeyType = int32(rei16)
  242. rei16, err = readInt16(eb, &p, &endian)
  243. if err != nil {
  244. return err
  245. }
  246. kl := int(rei16)
  247. ke.Key.KeyValue, err = readBytes(eb, &p, kl, &endian)
  248. if err != nil {
  249. return err
  250. }
  251. // The 32-bit key version overrides the 8-bit key version.
  252. // If at least 4 bytes are left after the other fields are read and they are non-zero
  253. // this indicates the 32-bit version is present.
  254. if len(eb)-p >= 4 {
  255. // The 32-bit key may be present
  256. ri32, err := readInt32(eb, &p, &endian)
  257. if err != nil {
  258. return err
  259. }
  260. ke.KVNO = uint32(ri32)
  261. }
  262. if ke.KVNO == 0 {
  263. // Handles if the value from the last 4 bytes was zero and also if there are not the 4 bytes present. Makes sense to put the same value here as KVNO8
  264. ke.KVNO = uint32(ke.KVNO8)
  265. }
  266. // Add the entry to the keytab
  267. kt.Entries = append(kt.Entries, ke)
  268. }
  269. // Check if there are still 4 bytes left to read
  270. // Also check that n is greater than zero
  271. if n < 0 || n > len(b) || len(b[n:]) < 4 {
  272. break
  273. }
  274. // Read the size of the next entry
  275. l, err = readInt32(b, &n, &endian)
  276. if err != nil {
  277. return err
  278. }
  279. }
  280. return nil
  281. }
  282. func (e entry) marshal(v int) ([]byte, error) {
  283. var b []byte
  284. pb, err := e.Principal.marshal(v)
  285. if err != nil {
  286. return b, err
  287. }
  288. b = append(b, pb...)
  289. var endian binary.ByteOrder
  290. endian = binary.BigEndian
  291. if v == 1 && isNativeEndianLittle() {
  292. endian = binary.LittleEndian
  293. }
  294. t := make([]byte, 9)
  295. endian.PutUint32(t[0:4], uint32(e.Timestamp.Unix()))
  296. t[4] = e.KVNO8
  297. endian.PutUint16(t[5:7], uint16(e.Key.KeyType))
  298. endian.PutUint16(t[7:9], uint16(len(e.Key.KeyValue)))
  299. b = append(b, t...)
  300. buf := new(bytes.Buffer)
  301. err = binary.Write(buf, endian, e.Key.KeyValue)
  302. if err != nil {
  303. return b, err
  304. }
  305. b = append(b, buf.Bytes()...)
  306. t = make([]byte, 4)
  307. endian.PutUint32(t, e.KVNO)
  308. b = append(b, t...)
  309. // Add the length header
  310. t = make([]byte, 4)
  311. endian.PutUint32(t, uint32(len(b)))
  312. b = append(t, b...)
  313. return b, nil
  314. }
  315. // Parse the Keytab bytes of a principal into a Keytab entry's principal.
  316. func parsePrincipal(b []byte, p *int, kt *Keytab, ke *entry, e *binary.ByteOrder) error {
  317. var err error
  318. ke.Principal.NumComponents, err = readInt16(b, p, e)
  319. if err != nil {
  320. return err
  321. }
  322. if kt.version == 1 {
  323. //In version 1 the number of components includes the realm. Minus 1 to make consistent with version 2
  324. ke.Principal.NumComponents--
  325. }
  326. lenRealm, err := readInt16(b, p, e)
  327. if err != nil {
  328. return err
  329. }
  330. realmB, err := readBytes(b, p, int(lenRealm), e)
  331. if err != nil {
  332. return err
  333. }
  334. ke.Principal.Realm = string(realmB)
  335. for i := 0; i < int(ke.Principal.NumComponents); i++ {
  336. l, err := readInt16(b, p, e)
  337. if err != nil {
  338. return err
  339. }
  340. compB, err := readBytes(b, p, int(l), e)
  341. if err != nil {
  342. return err
  343. }
  344. ke.Principal.Components = append(ke.Principal.Components, string(compB))
  345. }
  346. if kt.version != 1 {
  347. //Name Type is omitted in version 1
  348. ke.Principal.NameType, err = readInt32(b, p, e)
  349. if err != nil {
  350. return err
  351. }
  352. }
  353. return nil
  354. }
  355. func (p principal) marshal(v int) ([]byte, error) {
  356. //var b []byte
  357. b := make([]byte, 2)
  358. var endian binary.ByteOrder
  359. endian = binary.BigEndian
  360. if v == 1 && isNativeEndianLittle() {
  361. endian = binary.LittleEndian
  362. }
  363. endian.PutUint16(b[0:], uint16(p.NumComponents))
  364. realm, err := marshalString(p.Realm, v)
  365. if err != nil {
  366. return b, err
  367. }
  368. b = append(b, realm...)
  369. for _, c := range p.Components {
  370. cb, err := marshalString(c, v)
  371. if err != nil {
  372. return b, err
  373. }
  374. b = append(b, cb...)
  375. }
  376. if v != 1 {
  377. t := make([]byte, 4)
  378. endian.PutUint32(t, uint32(p.NameType))
  379. b = append(b, t...)
  380. }
  381. return b, nil
  382. }
  383. func marshalString(s string, v int) ([]byte, error) {
  384. sb := []byte(s)
  385. b := make([]byte, 2)
  386. var endian binary.ByteOrder
  387. endian = binary.BigEndian
  388. if v == 1 && isNativeEndianLittle() {
  389. endian = binary.LittleEndian
  390. }
  391. endian.PutUint16(b[0:], uint16(len(sb)))
  392. buf := new(bytes.Buffer)
  393. err := binary.Write(buf, endian, sb)
  394. if err != nil {
  395. return b, err
  396. }
  397. b = append(b, buf.Bytes()...)
  398. return b, err
  399. }
  400. // Read bytes representing a timestamp.
  401. func readTimestamp(b []byte, p *int, e *binary.ByteOrder) (time.Time, error) {
  402. i32, err := readInt32(b, p, e)
  403. if err != nil {
  404. return time.Time{}, err
  405. }
  406. return time.Unix(int64(i32), 0), nil
  407. }
  408. // Read bytes representing an eight bit integer.
  409. func readInt8(b []byte, p *int, e *binary.ByteOrder) (i int8, err error) {
  410. if *p < 0 {
  411. return 0, fmt.Errorf("%d cannot be less than zero", *p)
  412. }
  413. if (*p + 1) > len(b) {
  414. return 0, fmt.Errorf("%s's length is less than %d", b, *p+1)
  415. }
  416. buf := bytes.NewBuffer(b[*p : *p+1])
  417. binary.Read(buf, *e, &i)
  418. *p++
  419. return
  420. }
  421. // Read bytes representing a sixteen bit integer.
  422. func readInt16(b []byte, p *int, e *binary.ByteOrder) (i int16, err error) {
  423. if *p < 0 {
  424. return 0, fmt.Errorf("%d cannot be less than zero", *p)
  425. }
  426. if (*p + 2) > len(b) {
  427. return 0, fmt.Errorf("%s's length is less than %d", b, *p+2)
  428. }
  429. buf := bytes.NewBuffer(b[*p : *p+2])
  430. binary.Read(buf, *e, &i)
  431. *p += 2
  432. return
  433. }
  434. // Read bytes representing a thirty two bit integer.
  435. func readInt32(b []byte, p *int, e *binary.ByteOrder) (i int32, err error) {
  436. if *p < 0 {
  437. return 0, fmt.Errorf("%d cannot be less than zero", *p)
  438. }
  439. if (*p + 4) > len(b) {
  440. return 0, fmt.Errorf("%s's length is less than %d", b, *p+4)
  441. }
  442. buf := bytes.NewBuffer(b[*p : *p+4])
  443. binary.Read(buf, *e, &i)
  444. *p += 4
  445. return
  446. }
  447. func readBytes(b []byte, p *int, s int, e *binary.ByteOrder) ([]byte, error) {
  448. if s < 0 {
  449. return nil, fmt.Errorf("%d cannot be less than zero", s)
  450. }
  451. i := *p + s
  452. if i > len(b) {
  453. return nil, fmt.Errorf("%s's length is greater than %d", b, i)
  454. }
  455. buf := bytes.NewBuffer(b[*p:i])
  456. r := make([]byte, s)
  457. if err := binary.Read(buf, *e, &r); err != nil {
  458. return nil, err
  459. }
  460. *p += s
  461. return r, nil
  462. }
  463. func isNativeEndianLittle() bool {
  464. var x = 0x012345678
  465. var p = unsafe.Pointer(&x)
  466. var bp = (*[4]byte)(p)
  467. var endian bool
  468. if 0x01 == bp[0] {
  469. endian = false
  470. } else if (0x78 & 0xff) == (bp[0] & 0xff) {
  471. endian = true
  472. } else {
  473. // Default to big endian
  474. endian = false
  475. }
  476. return endian
  477. }
  478. // JSON return information about the keys held in the keytab in a JSON format.
  479. func (kt *Keytab) JSON() (string, error) {
  480. b, err := json.MarshalIndent(kt, "", " ")
  481. if err != nil {
  482. return "", err
  483. }
  484. return string(b), nil
  485. }