keytab.go 11 KB

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