KRBError.go 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Package messages implements Kerberos 5 message types and methods.
  2. package messages
  3. import (
  4. "fmt"
  5. "time"
  6. "github.com/jcmturner/gofork/encoding/asn1"
  7. "github.com/jcmturner/gokrb5/v8/asn1tools"
  8. "github.com/jcmturner/gokrb5/v8/iana"
  9. "github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
  10. "github.com/jcmturner/gokrb5/v8/iana/errorcode"
  11. "github.com/jcmturner/gokrb5/v8/iana/msgtype"
  12. "github.com/jcmturner/gokrb5/v8/krberror"
  13. "github.com/jcmturner/gokrb5/v8/types"
  14. )
  15. // KRBError implements RFC 4120 KRB_ERROR: https://tools.ietf.org/html/rfc4120#section-5.9.1.
  16. type KRBError struct {
  17. PVNO int `asn1:"explicit,tag:0"`
  18. MsgType int `asn1:"explicit,tag:1"`
  19. CTime time.Time `asn1:"generalized,optional,explicit,tag:2"`
  20. Cusec int `asn1:"optional,explicit,tag:3"`
  21. STime time.Time `asn1:"generalized,explicit,tag:4"`
  22. Susec int `asn1:"explicit,tag:5"`
  23. ErrorCode int32 `asn1:"explicit,tag:6"`
  24. CRealm string `asn1:"generalstring,optional,explicit,tag:7"`
  25. CName types.PrincipalName `asn1:"optional,explicit,tag:8"`
  26. Realm string `asn1:"generalstring,explicit,tag:9"`
  27. SName types.PrincipalName `asn1:"explicit,tag:10"`
  28. EText string `asn1:"generalstring,optional,explicit,tag:11"`
  29. EData []byte `asn1:"optional,explicit,tag:12"`
  30. }
  31. // NewKRBError creates a new KRBError.
  32. func NewKRBError(sname types.PrincipalName, realm string, code int32, etext string) KRBError {
  33. t := time.Now().UTC()
  34. return KRBError{
  35. PVNO: iana.PVNO,
  36. MsgType: msgtype.KRB_ERROR,
  37. STime: t,
  38. Susec: int((t.UnixNano() / int64(time.Microsecond)) - (t.Unix() * 1e6)),
  39. ErrorCode: code,
  40. SName: sname,
  41. Realm: realm,
  42. EText: etext,
  43. }
  44. }
  45. // Unmarshal bytes b into the KRBError struct.
  46. func (k *KRBError) Unmarshal(b []byte) error {
  47. _, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBError))
  48. if err != nil {
  49. return krberror.Errorf(err, krberror.EncodingError, "KRB_ERROR unmarshal error")
  50. }
  51. expectedMsgType := msgtype.KRB_ERROR
  52. if k.MsgType != expectedMsgType {
  53. return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a KRB_ERROR. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
  54. }
  55. return nil
  56. }
  57. // Marshal a KRBError into bytes.
  58. func (k *KRBError) Marshal() ([]byte, error) {
  59. b, err := asn1.Marshal(*k)
  60. if err != nil {
  61. return b, krberror.Errorf(err, krberror.EncodingError, "error marshaling KRBError")
  62. }
  63. b = asn1tools.AddASNAppTag(b, asnAppTag.KRBError)
  64. return b, nil
  65. }
  66. // Error method implementing error interface on KRBError struct.
  67. func (k KRBError) Error() string {
  68. etxt := fmt.Sprintf("KRB Error: %s", errorcode.Lookup(k.ErrorCode))
  69. if k.EText != "" {
  70. etxt = fmt.Sprintf("%s - %s", etxt, k.EText)
  71. }
  72. return etxt
  73. }
  74. func processUnmarshalReplyError(b []byte, err error) error {
  75. switch err.(type) {
  76. case asn1.StructuralError:
  77. var krberr KRBError
  78. tmperr := krberr.Unmarshal(b)
  79. if tmperr != nil {
  80. return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply")
  81. }
  82. return krberr
  83. default:
  84. return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply")
  85. }
  86. }