KDCRep.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. package messages
  2. // Reference: https://www.ietf.org/rfc/rfc4120.txt
  3. // Section: 5.4.2
  4. import (
  5. "fmt"
  6. "time"
  7. "github.com/jcmturner/gofork/encoding/asn1"
  8. "github.com/jcmturner/gokrb5/v8/asn1tools"
  9. "github.com/jcmturner/gokrb5/v8/config"
  10. "github.com/jcmturner/gokrb5/v8/credentials"
  11. "github.com/jcmturner/gokrb5/v8/crypto"
  12. "github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
  13. "github.com/jcmturner/gokrb5/v8/iana/flags"
  14. "github.com/jcmturner/gokrb5/v8/iana/keyusage"
  15. "github.com/jcmturner/gokrb5/v8/iana/msgtype"
  16. "github.com/jcmturner/gokrb5/v8/iana/patype"
  17. "github.com/jcmturner/gokrb5/v8/krberror"
  18. "github.com/jcmturner/gokrb5/v8/types"
  19. )
  20. type marshalKDCRep struct {
  21. PVNO int `asn1:"explicit,tag:0"`
  22. MsgType int `asn1:"explicit,tag:1"`
  23. PAData types.PADataSequence `asn1:"explicit,optional,tag:2"`
  24. CRealm string `asn1:"generalstring,explicit,tag:3"`
  25. CName types.PrincipalName `asn1:"explicit,tag:4"`
  26. // Ticket needs to be a raw value as it is wrapped in an APPLICATION tag
  27. Ticket asn1.RawValue `asn1:"explicit,tag:5"`
  28. EncPart types.EncryptedData `asn1:"explicit,tag:6"`
  29. }
  30. // KDCRepFields represents the KRB_KDC_REP fields.
  31. type KDCRepFields struct {
  32. PVNO int
  33. MsgType int
  34. PAData []types.PAData
  35. CRealm string
  36. CName types.PrincipalName
  37. Ticket Ticket
  38. EncPart types.EncryptedData
  39. DecryptedEncPart EncKDCRepPart
  40. }
  41. // ASRep implements RFC 4120 KRB_AS_REP: https://tools.ietf.org/html/rfc4120#section-5.4.2.
  42. type ASRep struct {
  43. KDCRepFields
  44. }
  45. // TGSRep implements RFC 4120 KRB_TGS_REP: https://tools.ietf.org/html/rfc4120#section-5.4.2.
  46. type TGSRep struct {
  47. KDCRepFields
  48. }
  49. // EncKDCRepPart is the encrypted part of KRB_KDC_REP.
  50. type EncKDCRepPart struct {
  51. Key types.EncryptionKey `asn1:"explicit,tag:0"`
  52. LastReqs []LastReq `asn1:"explicit,tag:1"`
  53. Nonce int `asn1:"explicit,tag:2"`
  54. KeyExpiration time.Time `asn1:"generalized,explicit,optional,tag:3"`
  55. Flags asn1.BitString `asn1:"explicit,tag:4"`
  56. AuthTime time.Time `asn1:"generalized,explicit,tag:5"`
  57. StartTime time.Time `asn1:"generalized,explicit,optional,tag:6"`
  58. EndTime time.Time `asn1:"generalized,explicit,tag:7"`
  59. RenewTill time.Time `asn1:"generalized,explicit,optional,tag:8"`
  60. SRealm string `asn1:"generalstring,explicit,tag:9"`
  61. SName types.PrincipalName `asn1:"explicit,tag:10"`
  62. CAddr []types.HostAddress `asn1:"explicit,optional,tag:11"`
  63. EncPAData types.PADataSequence `asn1:"explicit,optional,tag:12"`
  64. }
  65. // LastReq part of KRB_KDC_REP.
  66. type LastReq struct {
  67. LRType int32 `asn1:"explicit,tag:0"`
  68. LRValue time.Time `asn1:"generalized,explicit,tag:1"`
  69. }
  70. // Unmarshal bytes b into the ASRep struct.
  71. func (k *ASRep) Unmarshal(b []byte) error {
  72. var m marshalKDCRep
  73. _, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.ASREP))
  74. if err != nil {
  75. return processUnmarshalReplyError(b, err)
  76. }
  77. if m.MsgType != msgtype.KRB_AS_REP {
  78. return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate an AS_REP. Expected: %v; Actual: %v", msgtype.KRB_AS_REP, m.MsgType)
  79. }
  80. //Process the raw ticket within
  81. tkt, err := unmarshalTicket(m.Ticket.Bytes)
  82. if err != nil {
  83. return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling Ticket within AS_REP")
  84. }
  85. k.KDCRepFields = KDCRepFields{
  86. PVNO: m.PVNO,
  87. MsgType: m.MsgType,
  88. PAData: m.PAData,
  89. CRealm: m.CRealm,
  90. CName: m.CName,
  91. Ticket: tkt,
  92. EncPart: m.EncPart,
  93. }
  94. return nil
  95. }
  96. // Marshal ASRep struct.
  97. func (k *ASRep) Marshal() ([]byte, error) {
  98. m := marshalKDCRep{
  99. PVNO: k.PVNO,
  100. MsgType: k.MsgType,
  101. PAData: k.PAData,
  102. CRealm: k.CRealm,
  103. CName: k.CName,
  104. EncPart: k.EncPart,
  105. }
  106. b, err := k.Ticket.Marshal()
  107. if err != nil {
  108. return []byte{}, err
  109. }
  110. m.Ticket = asn1.RawValue{
  111. Class: asn1.ClassContextSpecific,
  112. IsCompound: true,
  113. Tag: 5,
  114. Bytes: b,
  115. }
  116. mk, err := asn1.Marshal(m)
  117. if err != nil {
  118. return mk, krberror.Errorf(err, krberror.EncodingError, "error marshaling AS_REP")
  119. }
  120. mk = asn1tools.AddASNAppTag(mk, asnAppTag.ASREP)
  121. return mk, nil
  122. }
  123. // Unmarshal bytes b into the TGSRep struct.
  124. func (k *TGSRep) Unmarshal(b []byte) error {
  125. var m marshalKDCRep
  126. _, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.TGSREP))
  127. if err != nil {
  128. return processUnmarshalReplyError(b, err)
  129. }
  130. if m.MsgType != msgtype.KRB_TGS_REP {
  131. return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate an TGS_REP. Expected: %v; Actual: %v", msgtype.KRB_TGS_REP, m.MsgType)
  132. }
  133. //Process the raw ticket within
  134. tkt, err := unmarshalTicket(m.Ticket.Bytes)
  135. if err != nil {
  136. return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling Ticket within TGS_REP")
  137. }
  138. k.KDCRepFields = KDCRepFields{
  139. PVNO: m.PVNO,
  140. MsgType: m.MsgType,
  141. PAData: m.PAData,
  142. CRealm: m.CRealm,
  143. CName: m.CName,
  144. Ticket: tkt,
  145. EncPart: m.EncPart,
  146. }
  147. return nil
  148. }
  149. // Marshal TGSRep struct.
  150. func (k *TGSRep) Marshal() ([]byte, error) {
  151. m := marshalKDCRep{
  152. PVNO: k.PVNO,
  153. MsgType: k.MsgType,
  154. PAData: k.PAData,
  155. CRealm: k.CRealm,
  156. CName: k.CName,
  157. EncPart: k.EncPart,
  158. }
  159. b, err := k.Ticket.Marshal()
  160. if err != nil {
  161. return []byte{}, err
  162. }
  163. m.Ticket = asn1.RawValue{
  164. Class: asn1.ClassContextSpecific,
  165. IsCompound: true,
  166. Tag: 5,
  167. Bytes: b,
  168. }
  169. mk, err := asn1.Marshal(m)
  170. if err != nil {
  171. return mk, krberror.Errorf(err, krberror.EncodingError, "error marshaling TGS_REP")
  172. }
  173. mk = asn1tools.AddASNAppTag(mk, asnAppTag.TGSREP)
  174. return mk, nil
  175. }
  176. // Unmarshal bytes b into encrypted part of KRB_KDC_REP.
  177. func (e *EncKDCRepPart) Unmarshal(b []byte) error {
  178. _, err := asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncASRepPart))
  179. if err != nil {
  180. // Try using tag 26
  181. // Ref: RFC 4120 - mentions that some implementations use application tag number 26 wether or not the reply is
  182. // a AS-REP or a TGS-REP.
  183. _, err = asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncTGSRepPart))
  184. if err != nil {
  185. return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling encrypted part within KDC_REP")
  186. }
  187. }
  188. return nil
  189. }
  190. // Marshal encrypted part of KRB_KDC_REP.
  191. func (e *EncKDCRepPart) Marshal() ([]byte, error) {
  192. b, err := asn1.Marshal(*e)
  193. if err != nil {
  194. return b, krberror.Errorf(err, krberror.EncodingError, "marshaling error of AS_REP encpart")
  195. }
  196. b = asn1tools.AddASNAppTag(b, asnAppTag.EncASRepPart)
  197. return b, nil
  198. }
  199. // DecryptEncPart decrypts the encrypted part of an AS_REP.
  200. func (k *ASRep) DecryptEncPart(c *credentials.Credentials) (types.EncryptionKey, error) {
  201. var key types.EncryptionKey
  202. var err error
  203. if c.HasKeytab() {
  204. key, _, err = c.Keytab().GetEncryptionKey(k.CName, k.CRealm, k.EncPart.KVNO, k.EncPart.EType)
  205. if err != nil {
  206. return key, krberror.Errorf(err, krberror.DecryptingError, "error decrypting AS_REP encrypted part")
  207. }
  208. }
  209. if c.HasPassword() {
  210. key, _, err = crypto.GetKeyFromPassword(c.Password(), k.CName, k.CRealm, k.EncPart.EType, k.PAData)
  211. if err != nil {
  212. return key, krberror.Errorf(err, krberror.DecryptingError, "error decrypting AS_REP encrypted part")
  213. }
  214. }
  215. if !c.HasKeytab() && !c.HasPassword() {
  216. return key, krberror.NewErrorf(krberror.DecryptingError, "no secret available in credentials to perform decryption of AS_REP encrypted part")
  217. }
  218. b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.AS_REP_ENCPART)
  219. if err != nil {
  220. return key, krberror.Errorf(err, krberror.DecryptingError, "error decrypting AS_REP encrypted part")
  221. }
  222. var denc EncKDCRepPart
  223. err = denc.Unmarshal(b)
  224. if err != nil {
  225. return key, krberror.Errorf(err, krberror.EncodingError, "error unmarshaling decrypted encpart of AS_REP")
  226. }
  227. k.DecryptedEncPart = denc
  228. return key, nil
  229. }
  230. // Verify checks the validity of AS_REP message.
  231. func (k *ASRep) Verify(cfg *config.Config, creds *credentials.Credentials, asReq ASReq) (bool, error) {
  232. //Ref RFC 4120 Section 3.1.5
  233. if !k.CName.Equal(asReq.ReqBody.CName) {
  234. return false, krberror.NewErrorf(krberror.KRBMsgError, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.CName, k.CName)
  235. }
  236. if k.CRealm != asReq.ReqBody.Realm {
  237. return false, krberror.NewErrorf(krberror.KRBMsgError, "CRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.CRealm)
  238. }
  239. key, err := k.DecryptEncPart(creds)
  240. if err != nil {
  241. return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting EncPart of AS_REP")
  242. }
  243. if k.DecryptedEncPart.Nonce != asReq.ReqBody.Nonce {
  244. return false, krberror.NewErrorf(krberror.KRBMsgError, "possible replay attack, nonce in response does not match that in request")
  245. }
  246. if !k.DecryptedEncPart.SName.Equal(asReq.ReqBody.SName) {
  247. return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %v; Reply: %v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
  248. }
  249. if k.DecryptedEncPart.SRealm != asReq.ReqBody.Realm {
  250. return false, krberror.NewErrorf(krberror.KRBMsgError, "SRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
  251. }
  252. if len(asReq.ReqBody.Addresses) > 0 {
  253. if !types.HostAddressesEqual(k.DecryptedEncPart.CAddr, asReq.ReqBody.Addresses) {
  254. return false, krberror.NewErrorf(krberror.KRBMsgError, "addresses listed in the AS_REP does not match those listed in the AS_REQ")
  255. }
  256. }
  257. t := time.Now().UTC()
  258. if t.Sub(k.DecryptedEncPart.AuthTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.AuthTime.Sub(t) > cfg.LibDefaults.Clockskew {
  259. return false, krberror.NewErrorf(krberror.KRBMsgError, "clock skew with KDC too large. Greater than %v seconds", cfg.LibDefaults.Clockskew.Seconds())
  260. }
  261. // RFC 6806 https://tools.ietf.org/html/rfc6806.html#section-11
  262. if asReq.PAData.Contains(patype.PA_REQ_ENC_PA_REP) && types.IsFlagSet(&k.DecryptedEncPart.Flags, flags.EncPARep) {
  263. if len(k.DecryptedEncPart.EncPAData) < 2 || !k.DecryptedEncPart.EncPAData.Contains(patype.PA_FX_FAST) {
  264. return false, krberror.NewErrorf(krberror.KRBMsgError, "KDC did not respond appropriately to FAST negotiation")
  265. }
  266. for _, pa := range k.DecryptedEncPart.EncPAData {
  267. if pa.PADataType == patype.PA_REQ_ENC_PA_REP {
  268. var pafast types.PAReqEncPARep
  269. err := pafast.Unmarshal(pa.PADataValue)
  270. if err != nil {
  271. return false, krberror.Errorf(err, krberror.EncodingError, "KDC FAST negotiation response error, could not unmarshal PA_REQ_ENC_PA_REP")
  272. }
  273. etype, err := crypto.GetChksumEtype(pafast.ChksumType)
  274. if err != nil {
  275. return false, krberror.Errorf(err, krberror.ChksumError, "KDC FAST negotiation response error")
  276. }
  277. ab, _ := asReq.Marshal()
  278. if !etype.VerifyChecksum(key.KeyValue, ab, pafast.Chksum, keyusage.KEY_USAGE_AS_REQ) {
  279. return false, krberror.Errorf(err, krberror.ChksumError, "KDC FAST negotiation response checksum invalid")
  280. }
  281. }
  282. }
  283. }
  284. return true, nil
  285. }
  286. // DecryptEncPart decrypts the encrypted part of an TGS_REP.
  287. func (k *TGSRep) DecryptEncPart(key types.EncryptionKey) error {
  288. b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.TGS_REP_ENCPART_SESSION_KEY)
  289. if err != nil {
  290. return krberror.Errorf(err, krberror.DecryptingError, "error decrypting TGS_REP EncPart")
  291. }
  292. var denc EncKDCRepPart
  293. err = denc.Unmarshal(b)
  294. if err != nil {
  295. return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling encrypted part")
  296. }
  297. k.DecryptedEncPart = denc
  298. return nil
  299. }
  300. // Verify checks the validity of the TGS_REP message.
  301. func (k *TGSRep) Verify(cfg *config.Config, tgsReq TGSReq) (bool, error) {
  302. if !k.CName.Equal(tgsReq.ReqBody.CName) {
  303. return false, krberror.NewErrorf(krberror.KRBMsgError, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.CName, k.CName)
  304. }
  305. if k.Ticket.Realm != tgsReq.ReqBody.Realm {
  306. return false, krberror.NewErrorf(krberror.KRBMsgError, "realm in response ticket does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.Ticket.Realm)
  307. }
  308. if k.DecryptedEncPart.Nonce != tgsReq.ReqBody.Nonce {
  309. return false, krberror.NewErrorf(krberror.KRBMsgError, "possible replay attack, nonce in response does not match that in request")
  310. }
  311. //if k.Ticket.SName.NameType != tgsReq.ReqBody.SName.NameType || k.Ticket.SName.NameString == nil {
  312. // return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response ticket does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.Ticket.SName)
  313. //}
  314. //for i := range k.Ticket.SName.NameString {
  315. // if k.Ticket.SName.NameString[i] != tgsReq.ReqBody.SName.NameString[i] {
  316. // return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response ticket does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.Ticket.SName)
  317. // }
  318. //}
  319. //if k.DecryptedEncPart.SName.NameType != tgsReq.ReqBody.SName.NameType || k.DecryptedEncPart.SName.NameString == nil {
  320. // return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
  321. //}
  322. //for i := range k.DecryptedEncPart.SName.NameString {
  323. // if k.DecryptedEncPart.SName.NameString[i] != tgsReq.ReqBody.SName.NameString[i] {
  324. // return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
  325. // }
  326. //}
  327. if k.DecryptedEncPart.SRealm != tgsReq.ReqBody.Realm {
  328. return false, krberror.NewErrorf(krberror.KRBMsgError, "SRealm in response does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
  329. }
  330. if len(k.DecryptedEncPart.CAddr) > 0 {
  331. if !types.HostAddressesEqual(k.DecryptedEncPart.CAddr, tgsReq.ReqBody.Addresses) {
  332. return false, krberror.NewErrorf(krberror.KRBMsgError, "addresses listed in the TGS_REP does not match those listed in the TGS_REQ")
  333. }
  334. }
  335. if time.Since(k.DecryptedEncPart.StartTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.StartTime.Sub(time.Now().UTC()) > cfg.LibDefaults.Clockskew {
  336. if time.Since(k.DecryptedEncPart.AuthTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.AuthTime.Sub(time.Now().UTC()) > cfg.LibDefaults.Clockskew {
  337. return false, krberror.NewErrorf(krberror.KRBMsgError, "clock skew with KDC too large. Greater than %v seconds.", cfg.LibDefaults.Clockskew.Seconds())
  338. }
  339. }
  340. return true, nil
  341. }