keytab.go 11 KB

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