ASExchange.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package client
  2. import (
  3. "github.com/jcmturner/gokrb5/crypto"
  4. "github.com/jcmturner/gokrb5/iana/errorcode"
  5. "github.com/jcmturner/gokrb5/iana/keyusage"
  6. "github.com/jcmturner/gokrb5/iana/patype"
  7. "github.com/jcmturner/gokrb5/krberror"
  8. "github.com/jcmturner/gokrb5/messages"
  9. "github.com/jcmturner/gokrb5/types"
  10. "sort"
  11. )
  12. // ASExchange performs an AS exchange for the client to retrieve a TGT.
  13. func (cl *Client) ASExchange() error {
  14. if ok, err := cl.IsConfigured(); !ok {
  15. return krberror.Errorf(err, krberror.ConfigError, "AS Exchange cannot be preformed")
  16. }
  17. ASReq, err := messages.NewASReq(cl.Config, cl.Credentials.CName)
  18. if err != nil {
  19. return krberror.Errorf(err, krberror.KRBMsgError, "Error generating new AS_REQ")
  20. }
  21. err = setPAData(cl, messages.KRBError{}, &ASReq)
  22. if err != nil {
  23. return krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: failed setting AS_REQ PAData")
  24. }
  25. b, err := ASReq.Marshal()
  26. if err != nil {
  27. return krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ")
  28. }
  29. var ASRep messages.ASRep
  30. rb, err := cl.SendToKDC(b)
  31. if err != nil {
  32. if e, ok := err.(messages.KRBError); ok && e.ErrorCode == errorcode.KDC_ERR_PREAUTH_REQUIRED {
  33. // From now on assume this client will need to do this pre-auth and set the PAData
  34. cl.GoKrb5Conf.AssumePAEncTimestampRequired = true
  35. err = setPAData(cl, e, &ASReq)
  36. if err != nil {
  37. return krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: failed setting AS_REQ PAData for pre-authentication required")
  38. }
  39. b, err := ASReq.Marshal()
  40. if err != nil {
  41. return krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ with PAData")
  42. }
  43. rb, err = cl.SendToKDC(b)
  44. if err != nil {
  45. return krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
  46. }
  47. } else {
  48. return krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
  49. }
  50. }
  51. err = ASRep.Unmarshal(rb)
  52. if err != nil {
  53. return krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed to process the AS_REP")
  54. }
  55. if ok, err := ASRep.IsValid(cl.Config, cl.Credentials, ASReq); !ok {
  56. return krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: AS_REP is not valid")
  57. }
  58. cl.session = &session{
  59. AuthTime: ASRep.DecryptedEncPart.AuthTime,
  60. EndTime: ASRep.DecryptedEncPart.EndTime,
  61. RenewTill: ASRep.DecryptedEncPart.RenewTill,
  62. TGT: ASRep.Ticket,
  63. SessionKey: ASRep.DecryptedEncPart.Key,
  64. SessionKeyExpiration: ASRep.DecryptedEncPart.KeyExpiration,
  65. }
  66. return nil
  67. }
  68. func setPAData(cl *Client, krberr messages.KRBError, ASReq *messages.ASReq) error {
  69. if !cl.GoKrb5Conf.DisablePAFXFast {
  70. pa := types.PAData{PADataType: patype.PA_REQ_ENC_PA_REP}
  71. ASReq.PAData = append(ASReq.PAData, pa)
  72. }
  73. if cl.GoKrb5Conf.AssumePAEncTimestampRequired {
  74. paTSb, err := types.GetPAEncTSEncAsnMarshalled()
  75. if err != nil {
  76. return krberror.Errorf(err, krberror.KRBMsgError, "Error creating PAEncTSEnc for Pre-Authentication")
  77. }
  78. sort.Sort(sort.Reverse(sort.IntSlice(cl.Config.LibDefaults.DefaultTktEnctypeIDs)))
  79. etype, err := crypto.GetEtype(cl.Config.LibDefaults.DefaultTktEnctypeIDs[0])
  80. if err != nil {
  81. return krberror.Errorf(err, krberror.EncryptingError, "Error creating etype")
  82. }
  83. key, err := cl.Key(etype, krberr)
  84. if err != nil {
  85. return krberror.Errorf(err, krberror.EncryptingError, "Error getting key from credentials")
  86. }
  87. paEncTS, err := crypto.GetEncryptedData(paTSb, key, keyusage.AS_REQ_PA_ENC_TIMESTAMP, 1)
  88. if err != nil {
  89. return krberror.Errorf(err, krberror.EncryptingError, "Error encrypting pre-authentication timestamp")
  90. }
  91. pb, err := paEncTS.Marshal()
  92. if err != nil {
  93. return krberror.Errorf(err, krberror.EncodingError, "Error marshaling the PAEncTSEnc encrypted data")
  94. }
  95. pa := types.PAData{
  96. PADataType: patype.PA_ENC_TIMESTAMP,
  97. PADataValue: pb,
  98. }
  99. ASReq.PAData = append(ASReq.PAData, pa)
  100. }
  101. return nil
  102. }