pac_type.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package pac
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "log"
  7. "gopkg.in/jcmturner/gokrb5.v7/crypto"
  8. "gopkg.in/jcmturner/gokrb5.v7/iana/keyusage"
  9. "gopkg.in/jcmturner/gokrb5.v7/types"
  10. "gopkg.in/jcmturner/rpc.v1/mstypes"
  11. )
  12. const (
  13. infoTypeKerbValidationInfo uint32 = 1
  14. infoTypeCredentials uint32 = 2
  15. infoTypePACServerSignatureData uint32 = 6
  16. infoTypePACKDCSignatureData uint32 = 7
  17. infoTypePACClientInfo uint32 = 10
  18. infoTypeS4UDelegationInfo uint32 = 11
  19. infoTypeUPNDNSInfo uint32 = 12
  20. infoTypePACClientClaimsInfo uint32 = 13
  21. infoTypePACDeviceInfo uint32 = 14
  22. infoTypePACDeviceClaimsInfo uint32 = 15
  23. )
  24. // PACType implements: https://msdn.microsoft.com/en-us/library/cc237950.aspx
  25. type PACType struct {
  26. CBuffers uint32
  27. Version uint32
  28. Buffers []InfoBuffer
  29. Data []byte
  30. KerbValidationInfo *KerbValidationInfo
  31. CredentialsInfo *CredentialsInfo
  32. ServerChecksum *SignatureData
  33. KDCChecksum *SignatureData
  34. ClientInfo *ClientInfo
  35. S4UDelegationInfo *S4UDelegationInfo
  36. UPNDNSInfo *UPNDNSInfo
  37. ClientClaimsInfo *ClientClaimsInfo
  38. DeviceInfo *DeviceInfo
  39. DeviceClaimsInfo *DeviceClaimsInfo
  40. ZeroSigData []byte
  41. }
  42. // InfoBuffer implements the PAC Info Buffer: https://msdn.microsoft.com/en-us/library/cc237954.aspx
  43. type InfoBuffer struct {
  44. ULType uint32 // A 32-bit unsigned integer in little-endian format that describes the type of data present in the buffer contained at Offset.
  45. CBBufferSize uint32 // A 32-bit unsigned integer in little-endian format that contains the size, in bytes, of the buffer in the PAC located at Offset.
  46. Offset uint64 // A 64-bit unsigned integer in little-endian format that contains the offset to the beginning of the buffer, in bytes, from the beginning of the PACTYPE structure. The data offset MUST be a multiple of eight. The following sections specify the format of each type of element.
  47. }
  48. // Unmarshal bytes into the PACType struct
  49. func (pac *PACType) Unmarshal(b []byte) (err error) {
  50. pac.Data = b
  51. zb := make([]byte, len(b), len(b))
  52. copy(zb, b)
  53. pac.ZeroSigData = zb
  54. r := mstypes.NewReader(bytes.NewReader(b))
  55. pac.CBuffers, err = r.Uint32()
  56. if err != nil {
  57. return
  58. }
  59. pac.Version, err = r.Uint32()
  60. if err != nil {
  61. return
  62. }
  63. buf := make([]InfoBuffer, pac.CBuffers, pac.CBuffers)
  64. for i := range buf {
  65. buf[i].ULType, err = r.Uint32()
  66. if err != nil {
  67. return
  68. }
  69. buf[i].CBBufferSize, err = r.Uint32()
  70. if err != nil {
  71. return
  72. }
  73. buf[i].Offset, err = r.Uint64()
  74. if err != nil {
  75. return
  76. }
  77. }
  78. pac.Buffers = buf
  79. return nil
  80. }
  81. // ProcessPACInfoBuffers processes the PAC Info Buffers.
  82. // https://msdn.microsoft.com/en-us/library/cc237954.aspx
  83. func (pac *PACType) ProcessPACInfoBuffers(key types.EncryptionKey, l *log.Logger) error {
  84. for _, buf := range pac.Buffers {
  85. p := make([]byte, buf.CBBufferSize, buf.CBBufferSize)
  86. copy(p, pac.Data[int(buf.Offset):int(buf.Offset)+int(buf.CBBufferSize)])
  87. switch buf.ULType {
  88. case infoTypeKerbValidationInfo:
  89. if pac.KerbValidationInfo != nil {
  90. //Must ignore subsequent buffers of this type
  91. continue
  92. }
  93. var k KerbValidationInfo
  94. err := k.Unmarshal(p)
  95. if err != nil {
  96. return fmt.Errorf("error processing KerbValidationInfo: %v", err)
  97. }
  98. pac.KerbValidationInfo = &k
  99. case infoTypeCredentials:
  100. // Currently PAC parsing is only useful on the service side in gokrb5
  101. // The CredentialsInfo are only useful when gokrb5 has implemented RFC4556 and only applied on the client side.
  102. // Skipping CredentialsInfo - will be revisited under RFC4556 implementation.
  103. continue
  104. //if pac.CredentialsInfo != nil {
  105. // //Must ignore subsequent buffers of this type
  106. // continue
  107. //}
  108. //var k CredentialsInfo
  109. //err := k.Unmarshal(p, key) // The encryption key used is the AS reply key only available to the client.
  110. //if err != nil {
  111. // return fmt.Errorf("error processing CredentialsInfo: %v", err)
  112. //}
  113. //pac.CredentialsInfo = &k
  114. case infoTypePACServerSignatureData:
  115. if pac.ServerChecksum != nil {
  116. //Must ignore subsequent buffers of this type
  117. continue
  118. }
  119. var k SignatureData
  120. zb, err := k.Unmarshal(p)
  121. copy(pac.ZeroSigData[int(buf.Offset):int(buf.Offset)+int(buf.CBBufferSize)], zb)
  122. if err != nil {
  123. return fmt.Errorf("error processing ServerChecksum: %v", err)
  124. }
  125. pac.ServerChecksum = &k
  126. case infoTypePACKDCSignatureData:
  127. if pac.KDCChecksum != nil {
  128. //Must ignore subsequent buffers of this type
  129. continue
  130. }
  131. var k SignatureData
  132. zb, err := k.Unmarshal(p)
  133. copy(pac.ZeroSigData[int(buf.Offset):int(buf.Offset)+int(buf.CBBufferSize)], zb)
  134. if err != nil {
  135. return fmt.Errorf("error processing KDCChecksum: %v", err)
  136. }
  137. pac.KDCChecksum = &k
  138. case infoTypePACClientInfo:
  139. if pac.ClientInfo != nil {
  140. //Must ignore subsequent buffers of this type
  141. continue
  142. }
  143. var k ClientInfo
  144. err := k.Unmarshal(p)
  145. if err != nil {
  146. return fmt.Errorf("error processing ClientInfo: %v", err)
  147. }
  148. pac.ClientInfo = &k
  149. case infoTypeS4UDelegationInfo:
  150. if pac.S4UDelegationInfo != nil {
  151. //Must ignore subsequent buffers of this type
  152. continue
  153. }
  154. var k S4UDelegationInfo
  155. err := k.Unmarshal(p)
  156. if err != nil {
  157. l.Printf("could not process S4U_DelegationInfo: %v", err)
  158. continue
  159. }
  160. pac.S4UDelegationInfo = &k
  161. case infoTypeUPNDNSInfo:
  162. if pac.UPNDNSInfo != nil {
  163. //Must ignore subsequent buffers of this type
  164. continue
  165. }
  166. var k UPNDNSInfo
  167. err := k.Unmarshal(p)
  168. if err != nil {
  169. l.Printf("could not process UPN_DNSInfo: %v", err)
  170. continue
  171. }
  172. pac.UPNDNSInfo = &k
  173. case infoTypePACClientClaimsInfo:
  174. if pac.ClientClaimsInfo != nil || len(p) < 1 {
  175. //Must ignore subsequent buffers of this type
  176. continue
  177. }
  178. var k ClientClaimsInfo
  179. err := k.Unmarshal(p)
  180. if err != nil {
  181. l.Printf("could not process ClientClaimsInfo: %v", err)
  182. continue
  183. }
  184. pac.ClientClaimsInfo = &k
  185. case infoTypePACDeviceInfo:
  186. if pac.DeviceInfo != nil {
  187. //Must ignore subsequent buffers of this type
  188. continue
  189. }
  190. var k DeviceInfo
  191. err := k.Unmarshal(p)
  192. if err != nil {
  193. l.Printf("could not process DeviceInfo: %v", err)
  194. continue
  195. }
  196. pac.DeviceInfo = &k
  197. case infoTypePACDeviceClaimsInfo:
  198. if pac.DeviceClaimsInfo != nil {
  199. //Must ignore subsequent buffers of this type
  200. continue
  201. }
  202. var k DeviceClaimsInfo
  203. err := k.Unmarshal(p)
  204. if err != nil {
  205. l.Printf("could not process DeviceClaimsInfo: %v", err)
  206. continue
  207. }
  208. pac.DeviceClaimsInfo = &k
  209. }
  210. }
  211. if ok, err := pac.verify(key); !ok {
  212. return err
  213. }
  214. return nil
  215. }
  216. func (pac *PACType) verify(key types.EncryptionKey) (bool, error) {
  217. if pac.KerbValidationInfo == nil {
  218. return false, errors.New("PAC Info Buffers does not contain a KerbValidationInfo")
  219. }
  220. if pac.ServerChecksum == nil {
  221. return false, errors.New("PAC Info Buffers does not contain a ServerChecksum")
  222. }
  223. if pac.KDCChecksum == nil {
  224. return false, errors.New("PAC Info Buffers does not contain a KDCChecksum")
  225. }
  226. if pac.ClientInfo == nil {
  227. return false, errors.New("PAC Info Buffers does not contain a ClientInfo")
  228. }
  229. etype, err := crypto.GetChksumEtype(int32(pac.ServerChecksum.SignatureType))
  230. if err != nil {
  231. return false, err
  232. }
  233. if ok := etype.VerifyChecksum(key.KeyValue,
  234. pac.ZeroSigData,
  235. pac.ServerChecksum.Signature,
  236. keyusage.KERB_NON_KERB_CKSUM_SALT); !ok {
  237. return false, errors.New("PAC service checksum verification failed")
  238. }
  239. return true, nil
  240. }