Ticket.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Kerberos 5 data types.
  2. package types
  3. import (
  4. "fmt"
  5. "github.com/jcmturner/asn1"
  6. "github.com/jcmturner/gokrb5/asn1tools"
  7. "github.com/jcmturner/gokrb5/iana/asnAppTag"
  8. "time"
  9. )
  10. // Reference: https://www.ietf.org/rfc/rfc4120.txt
  11. // Section: 5.3
  12. type Ticket struct {
  13. TktVNO int `asn1:"explicit,tag:0"`
  14. Realm string `asn1:"generalstring,explicit,tag:1"`
  15. SName PrincipalName `asn1:"explicit,tag:2"`
  16. EncPart EncryptedData `asn1:"explicit,tag:3"`
  17. }
  18. type EncTicketPart struct {
  19. Flags asn1.BitString `asn1:"explicit,tag:0"`
  20. Key EncryptionKey `asn1:"explicit,tag:1"`
  21. CRealm string `asn1:"generalstring,explicit,tag:2"`
  22. CName PrincipalName `asn1:"explicit,tag:3"`
  23. Transited TransitedEncoding `asn1:"explicit,tag:4"`
  24. AuthTime time.Time `asn1:"generalized,explicit,tag:5"`
  25. StartTime time.Time `asn1:"generalized,explicit,optional,tag:6"`
  26. EndTime time.Time `asn1:"generalized,explicit,tag:7"`
  27. RenewTill time.Time `asn1:"generalized,explicit,optional,tag:8"`
  28. CAddr HostAddresses `asn1:"explicit,optional,tag:9"`
  29. AuthorizationData AuthorizationData `asn1:"explicit,optional,tag:10"`
  30. }
  31. type TransitedEncoding struct {
  32. TRType int `asn1:"explicit,tag:0"`
  33. Contents []byte `asn1:"explicit,tag:1"`
  34. }
  35. func (t *Ticket) Unmarshal(b []byte) error {
  36. _, err := asn1.UnmarshalWithParams(b, t, fmt.Sprintf("application,explicit,tag:%d", asnAppTag.Ticket))
  37. return err
  38. }
  39. func (t *Ticket) Marshal() ([]byte, error) {
  40. b, err := asn1.Marshal(*t)
  41. if err != nil {
  42. return nil, err
  43. }
  44. b = asn1tools.AddASNAppTag(b, asnAppTag.Ticket)
  45. return b, nil
  46. }
  47. func (t *EncTicketPart) Unmarshal(b []byte) error {
  48. _, err := asn1.UnmarshalWithParams(b, t, fmt.Sprintf("application,explicit,tag:%d", asnAppTag.EncTicketPart))
  49. return err
  50. }
  51. func UnmarshalTicket(b []byte) (t Ticket, err error) {
  52. _, err = asn1.UnmarshalWithParams(b, &t, fmt.Sprintf("application,explicit,tag:%d", asnAppTag.Ticket))
  53. return
  54. }
  55. func UnmarshalTicketsSequence(in asn1.RawValue) ([]Ticket, error) {
  56. //This is a workaround to a asn1 decoding issue in golang - https://github.com/golang/go/issues/17321. It's not pretty I'm afraid
  57. //We pull out raw values from the larger raw value (that is actually the data of the sequence of raw values) and track our position moving along the data.
  58. b := in.Bytes
  59. // Ignore the head of the asn1 stream (3bytes) as this is what tells us its a sequence but we're handling it ourselves
  60. p := 3
  61. var tkts []Ticket
  62. var raw asn1.RawValue
  63. for p < (len(b)) {
  64. _, err := asn1.UnmarshalWithParams(b[p:], &raw, fmt.Sprintf("application,tag:%d", asnAppTag.Ticket))
  65. if err != nil {
  66. return nil, fmt.Errorf("Unmarshalling sequence of tickets failed geting length of ticket: %v", err)
  67. }
  68. t, err := UnmarshalTicket(b[p:])
  69. if err != nil {
  70. return nil, fmt.Errorf("Unmarshalling sequence of tickets failed: %v", err)
  71. }
  72. p += len(raw.FullBytes)
  73. tkts = append(tkts, t)
  74. }
  75. MarshalTicketSequence(tkts)
  76. return tkts, nil
  77. }
  78. func MarshalTicketSequence(tkts []Ticket) (asn1.RawValue, error) {
  79. raw := asn1.RawValue{
  80. Class: 2,
  81. IsCompound: true,
  82. }
  83. if len(tkts) < 1 {
  84. // There are no tickets to marshal
  85. return raw, nil
  86. }
  87. var btkts []byte
  88. for i, t := range tkts {
  89. b, err := t.Marshal()
  90. if err != nil {
  91. return raw, fmt.Errorf("Error marshalling ticket number %d in seqence of tickets", i+1)
  92. }
  93. btkts = append(btkts, b...)
  94. }
  95. // The ASN1 wrapping consists of 2 bytes:
  96. // 1st byte -> Identifier Octet - In this case an OCTET STRING (ASN TAG
  97. // 2nd byte -> The length (this will be the size indicated in the input bytes + 2 for the additional bytes we add here.
  98. // Application Tag:
  99. //| Byte: | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
  100. //| Value: | 0 | 1 | 1 | From the RFC spec 4120 |
  101. //| Explanation | Defined by the ASN1 encoding rules for an application tag | A value of 1 indicates a constructed type | The ASN Application tag value |
  102. btkts = append(asn1tools.MarshalLengthBytes(len(btkts)), btkts...)
  103. btkts = append([]byte{byte(32 + asn1.TagSequence)}, btkts...)
  104. raw.Bytes = btkts
  105. // If we need to create teh full bytes then identifier octect is "context-specific" = 128 + "constructed" + 32 + the wrapping explicit tag (11)
  106. //fmt.Fprintf(os.Stderr, "mRaw fb: %v\n", raw.FullBytes)
  107. return raw, nil
  108. }